Add Server

This commit is contained in:
PJ Dietz 2015-05-10 18:58:08 -04:00
parent 67d562b3bc
commit 0f9c5079f9
2 changed files with 310 additions and 0 deletions

146
src/Server.php Normal file
View File

@ -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
}

View File

@ -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();
}
}