Add Server
This commit is contained in:
parent
67d562b3bc
commit
0f9c5079f9
|
|
@ -0,0 +1,146 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace WellRESTed;
|
||||||
|
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use WellRESTed\Dispatching\Dispatcher;
|
||||||
|
use WellRESTed\Dispatching\DispatcherInterface;
|
||||||
|
use WellRESTed\Dispatching\DispatchStackInterface;
|
||||||
|
use WellRESTed\Message\Response;
|
||||||
|
use WellRESTed\Message\ServerRequest;
|
||||||
|
use WellRESTed\Responder\Responder;
|
||||||
|
use WellRESTed\Responder\ResponderInterface;
|
||||||
|
use WellRESTed\Routing\Router;
|
||||||
|
|
||||||
|
class Server implements DispatchStackInterface
|
||||||
|
{
|
||||||
|
/** @var DispatcherInterface */
|
||||||
|
private $dispatcher;
|
||||||
|
|
||||||
|
/** @var mixed[] List array of middleware */
|
||||||
|
private $stack;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->dispatcher = $this->getDispatcher();
|
||||||
|
$this->stack = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push a new middleware onto the stack.
|
||||||
|
*
|
||||||
|
* @param mixed $middleware Middleware to dispatch in sequence
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function add($middleware)
|
||||||
|
{
|
||||||
|
$this->stack[] = $middleware;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch the contained middleware in the order in which they were added.
|
||||||
|
*
|
||||||
|
* The first middleware added to the stack is the first to be dispatched.
|
||||||
|
*
|
||||||
|
* Each middleware, when dispatched, will receive a $next callable that
|
||||||
|
* dispatches the middleware that follows it. The only exception to this is
|
||||||
|
* the last middleware in the stack which much receive a $next callable the
|
||||||
|
* returns the response unchanged.
|
||||||
|
*
|
||||||
|
* If the instance is dispatched with no middleware added, the instance
|
||||||
|
* MUST call $next passing $request and $response and return the returned
|
||||||
|
* response.
|
||||||
|
*
|
||||||
|
* @param ServerRequestInterface $request
|
||||||
|
* @param ResponseInterface $response
|
||||||
|
* @param callable $next
|
||||||
|
* @return ResponseInterface
|
||||||
|
*/
|
||||||
|
public function dispatch(ServerRequestInterface $request, ResponseInterface $response, $next)
|
||||||
|
{
|
||||||
|
return $this->dispatcher->dispatch($this->stack, $request, $response, $next);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a new Router that uses the server's dispatcher.
|
||||||
|
*
|
||||||
|
* @return Router
|
||||||
|
*/
|
||||||
|
public function makeRouter()
|
||||||
|
{
|
||||||
|
return new Router($this->dispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the request-response cycle.
|
||||||
|
*
|
||||||
|
* This method reads a server request, dispatches the request through the
|
||||||
|
* server's stack of middleware, and outputs the response.
|
||||||
|
*/
|
||||||
|
public function respond()
|
||||||
|
{
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$response = $this->getResponse();
|
||||||
|
$next = function ($request, $response) {
|
||||||
|
return $response;
|
||||||
|
};
|
||||||
|
$response = $this->dispatch($request, $response, $next);
|
||||||
|
$responder = $this->getResponder();
|
||||||
|
$responder->respond($request, $response);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// The following method provide instances using default classes. To use
|
||||||
|
// custom classes, subclass Server and override methods as needed.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an instance to dispatch middleware.
|
||||||
|
*
|
||||||
|
* @return DispatcherInterface
|
||||||
|
*/
|
||||||
|
protected function getDispatcher()
|
||||||
|
{
|
||||||
|
return new Dispatcher();
|
||||||
|
}
|
||||||
|
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an instance representing the request submitted to the server.
|
||||||
|
*
|
||||||
|
* @return ServerRequestInterface
|
||||||
|
*/
|
||||||
|
protected function getRequest()
|
||||||
|
{
|
||||||
|
return ServerRequest::getServerRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an instance that will output the response to the client.
|
||||||
|
*
|
||||||
|
* @return ResponderInterface
|
||||||
|
*/
|
||||||
|
protected function getResponder()
|
||||||
|
{
|
||||||
|
return new Responder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a "blank" response instance to populate.
|
||||||
|
*
|
||||||
|
* The response will be dispatched through the middleware and eventually
|
||||||
|
* output to the client.
|
||||||
|
*
|
||||||
|
* @return ResponseInterface
|
||||||
|
*/
|
||||||
|
protected function getResponse()
|
||||||
|
{
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace WellRESTed\Test\Unit\Server;
|
||||||
|
|
||||||
|
use Prophecy\Argument;
|
||||||
|
use WellRESTed\Server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @coversDefaultClass WellRESTed\Server
|
||||||
|
* @uses WellRESTed\Server
|
||||||
|
*/
|
||||||
|
class ServerTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
private $dispatcher;
|
||||||
|
private $request;
|
||||||
|
private $response;
|
||||||
|
private $responder;
|
||||||
|
private $server;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
$this->request = $this->prophesize('Psr\Http\Message\ServerRequestInterface');
|
||||||
|
$this->response = $this->prophesize('Psr\Http\Message\ResponseInterface');
|
||||||
|
$this->responder = $this->prophesize('WellRESTed\Responder\ResponderInterface');
|
||||||
|
$this->responder->respond(Argument::cetera())->willReturn();
|
||||||
|
$this->dispatcher = $this->prophesize('WellRESTed\Dispatching\DispatcherInterface');
|
||||||
|
$this->dispatcher->dispatch(Argument::cetera())->will(
|
||||||
|
function ($args) {
|
||||||
|
list($middleware, $request, $response, $next) = $args;
|
||||||
|
return $next($request, $response);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->server = $this->getMockBuilder('WellRESTed\Server')
|
||||||
|
->setMethods(["getDispatcher", "getRequest", "getResponse", "getResponder"])
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$this->server->expects($this->any())
|
||||||
|
->method("getDispatcher")
|
||||||
|
->will($this->returnValue($this->dispatcher->reveal()));
|
||||||
|
$this->server->expects($this->any())
|
||||||
|
->method("getRequest")
|
||||||
|
->will($this->returnValue($this->request->reveal()));
|
||||||
|
$this->server->expects($this->any())
|
||||||
|
->method("getResponse")
|
||||||
|
->will($this->returnValue($this->response->reveal()));
|
||||||
|
$this->server->expects($this->any())
|
||||||
|
->method("getResponder")
|
||||||
|
->will($this->returnValue($this->responder->reveal()));
|
||||||
|
$this->server->__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers ::__construct
|
||||||
|
* @covers ::getDispatcher
|
||||||
|
* @uses WellRESTed\Dispatching\Dispatcher
|
||||||
|
*/
|
||||||
|
public function testCreatesInstances()
|
||||||
|
{
|
||||||
|
$server = new Server();
|
||||||
|
$this->assertNotNull($server);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers ::add
|
||||||
|
*/
|
||||||
|
public function testAddIsFluid()
|
||||||
|
{
|
||||||
|
$server = new Server();
|
||||||
|
$this->assertSame($server, $server->add("middleware"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers ::add
|
||||||
|
* @covers ::dispatch
|
||||||
|
*/
|
||||||
|
public function testDispatchesMiddlewareStack()
|
||||||
|
{
|
||||||
|
$next = function ($request, $response) {
|
||||||
|
return $response;
|
||||||
|
};
|
||||||
|
|
||||||
|
$this->server->add("first");
|
||||||
|
$this->server->add("second");
|
||||||
|
$this->server->add("third");
|
||||||
|
|
||||||
|
$this->server->dispatch($this->request->reveal(), $this->response->reveal(), $next);
|
||||||
|
|
||||||
|
$this->dispatcher->dispatch(
|
||||||
|
["first", "second", "third"],
|
||||||
|
$this->request->reveal(),
|
||||||
|
$this->response->reveal(),
|
||||||
|
$next
|
||||||
|
)->shouldHaveBeenCalled();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Respond
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers ::respond
|
||||||
|
*/
|
||||||
|
public function testRespondDispatchesRequest()
|
||||||
|
{
|
||||||
|
$this->server->respond();
|
||||||
|
$this->dispatcher->dispatch(
|
||||||
|
Argument::any(),
|
||||||
|
$this->request->reveal(),
|
||||||
|
Argument::any(),
|
||||||
|
Argument::any()
|
||||||
|
)->shouldHaveBeenCalled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers ::respond
|
||||||
|
*/
|
||||||
|
public function testRespondDispatchesResponse()
|
||||||
|
{
|
||||||
|
$this->server->respond();
|
||||||
|
$this->dispatcher->dispatch(
|
||||||
|
Argument::any(),
|
||||||
|
Argument::any(),
|
||||||
|
$this->response->reveal(),
|
||||||
|
Argument::any()
|
||||||
|
)->shouldHaveBeenCalled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers ::respond
|
||||||
|
*/
|
||||||
|
public function testRespondSendsResponseToResponder()
|
||||||
|
{
|
||||||
|
$this->server->respond();
|
||||||
|
$this->responder->respond(
|
||||||
|
$this->request->reveal(),
|
||||||
|
$this->response->reveal()
|
||||||
|
)->shouldHaveBeenCalled();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Router
|
||||||
|
|
||||||
|
public function testCreatesRouterWithDispatcher()
|
||||||
|
{
|
||||||
|
$this->request->getMethod()->willReturn("GET");
|
||||||
|
$this->request->getRequestTarget()->willReturn("/");
|
||||||
|
|
||||||
|
$next = function ($request, $response) {
|
||||||
|
return $response;
|
||||||
|
};
|
||||||
|
|
||||||
|
$router = $this->server->makeRouter();
|
||||||
|
$router->register("GET", "/", "middleware");
|
||||||
|
$router->dispatch($this->request->reveal(), $this->response->reveal(), $next);
|
||||||
|
|
||||||
|
$this->dispatcher->dispatch(
|
||||||
|
"middleware",
|
||||||
|
$this->request->reveal(),
|
||||||
|
$this->response->reveal(),
|
||||||
|
$next
|
||||||
|
)->shouldHaveBeenCalled();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue