diff --git a/composer.json b/composer.json index 4586b24..a1a5c53 100644 --- a/composer.json +++ b/composer.json @@ -11,4 +11,4 @@ "BitCommunism\\Http\\": "src/" } } -} +} \ No newline at end of file diff --git a/config/default.php b/config/default.php index 9d4eb66..533c428 100644 --- a/config/default.php +++ b/config/default.php @@ -10,7 +10,7 @@ use function DI\object; return [ 'marx.calls' => add([ 'http' => function(Server $server) { - $server->serve(); + return $server; } ]), diff --git a/src/Server.php b/src/Server.php index b1753d5..376a888 100644 --- a/src/Server.php +++ b/src/Server.php @@ -17,6 +17,7 @@ use function GuzzleHttp\Psr7\copy_to_stream; use GuzzleHttp\Psr7\Response; use GuzzleHttp\Psr7\ServerRequest; use function GuzzleHttp\Psr7\stream_for; +use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -24,6 +25,10 @@ class Server { private $routes = []; private $container; + + /** + * @var Dispatcher + */ private $router; public function __construct($routes, Container $container) @@ -78,12 +83,29 @@ class Server public function serve() { $request = ServerRequest::fromGlobals(); + + $response = $this->respond($request); + + header('HTTP/' . $response->getProtocolVersion() . ' ' . $response->getStatusCode() . ' ' . $response->getReasonPhrase()); + + $wrote = []; + foreach ($response->getHeaders() as [$headerName, $headerValue]) { + // Only replace header if we didn't write on those yet + header($headerName . ': ' . $headerValue, !isset($wrote[$headerName])); + $wrote[$headerName] = true; + } + + $stdout = fopen('php://output', 'w+'); + + copy_to_stream($response->getBody(), stream_for($stdout)); + } + + public function respond(ServerRequestInterface $request, ResponseInterface $response = null): ResponseInterface + { $path = $request->getUri()->getPath(); $method = $request->getMethod(); $routeInfo = $this->router->dispatch($method, $path); - $response = null; - switch ($routeInfo[0]) { case Dispatcher::NOT_FOUND: // todo: Error page @@ -93,7 +115,7 @@ class Server break; case Dispatcher::FOUND: [$_, $handler, $vars] = $routeInfo; - $response = $this->handleHttp($request, $handler, $vars); + $response = $this->handleHttp($request, $handler, $vars, $response); break; } @@ -101,50 +123,50 @@ class Server // todo: Error page } - header('Status: ' . $response->getStatusCode() . ' ' . $response->getReasonPhrase()); - - $wrote = []; - foreach ($response->getHeaders() as [$headerName, $headerValue]) { - // Only replace header if we didn't write on those yet - header($headerName . ': ' . $headerValue, !isset($wrote[$headerName])); - $wrote[$headerName] = true; - } - - $stdout = fopen('php://output', 'w+'); - - copy_to_stream($response->getBody(), stream_for($stdout)); + return $response; } - public function handleHttp(ServerRequestInterface $request, array $handler, array $vars): ResponseInterface + public function handleHttp(ServerRequestInterface $request, array $handler, array $vars, ResponseInterface $response = null): ResponseInterface { [$_, $_, $middlewareArray] = $handler; $middlewarePointer = 0; $next = null; - $response = new Response(200, [], stream_for('No answer')); + + if ($response === null) { + $response = new Response(200, [], stream_for('No answer')); + } $next = function ($request, $response, $vars) use ($handler, $middlewareArray, &$middlewarePointer, &$next) { $output = null; if (count($middlewareArray) >= $middlewarePointer) { $obj = $this->container->get($handler[0]); - $output = $obj->{$handler[1]}($request, $response, $vars); + $call = [$obj, $handler[1]]; } else { - [$name, $func] = $middlewareArray[$middlewarePointer++]; - $middleware = $this->container->get($name); - $output = $middleware->{$func}($request, $response, $vars); + $call = [$middleware, $func]; } + $output = $this->container->call($call, [ + RequestInterface::class => $request, + ResponseInterface::class => $response, + 'request' => $request, + 'response' => $response, + 'vars' => $vars, + ]); + + return $this->normalizeResponse($output, $response); }; return $next($request, $response, $vars); } - private function normalizeResponse($response, ResponseInterface $previousResponse) { + private function normalizeResponse($response, ResponseInterface $previousResponse) + { if ($response instanceof ResponseInterface) { return $response; }