Merge pull request 'add generic HttpResponse' (#6) from feature/create-generic-class-for-http-response into master
All checks were successful
soko-web/pipeline/head This commit looks good

Reviewed-on: #6
This commit is contained in:
Bence Pőcze 2023-04-16 20:52:06 +02:00
commit 948b36c80d
Signed by: Gitea
GPG Key ID: 7B89B83EED9AD2C6

View File

@ -0,0 +1,109 @@
<?php namespace SokoWeb\Response;
use SokoWeb\Interfaces\Response\IRedirect;
use SokoWeb\Interfaces\Response\IContent;
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
use SokoWeb\Interfaces\Authorization\ISecured;
use SokoWeb\Interfaces\Request\IRequest;
use SokoWeb\Response\Redirect;
use SokoWeb\Response\HtmlContent;
use SokoWeb\Response\JsonContent;
use SokoWeb\Routing\RouteCollection;
class HttpResponse
{
private IRequest $request;
private RouteCollection $routeCollection;
private array $appConfig;
private string $method;
private string $rawUrl;
private array $parsedUrl;
public function __construct(
IRequest $request,
RouteCollection $routeCollection,
array $appConfig,
string $requestMethod,
string $requestUrl
) {
$this->request = $request;
$this->routeCollection = $routeCollection;
$this->appConfig = $appConfig;
$this->method = strtolower($requestMethod);
$this->parsedUrl = parse_url($requestUrl);
$this->rawUrl = $requestUrl;
}
public function render(): void
{
$match = $this->routeCollection->match($this->method, $this->parsedUrl['path']);
if ($match === null) {
$this->render404();
return;
}
list($route, $params) = $match;
$this->request->setParsedRouteParams($params);
$handler = $route->getHandler();
$controller = new $handler[0]($this->request);
if (
$controller instanceof IAuthenticationRequired &&
$controller->isAuthenticationRequired() &&
$this->request->user() === null
) {
$this->redirectToLogin();
return;
}
if (
$this->method === 'post' &&
!in_array($this->parsedUrl['path'], $this->appConfig['antiCsrfTokenExceptions']) &&
$this->request->post($this->appConfig['antiCsrfTokenName']) !== $this->request->session()->get($this->appConfig['antiCsrfTokenName'])
) {
$this->renderAntiCsrfError();
return;
}
if ($controller instanceof ISecured && !$controller->authorize()) {
$this->render404();
return;
}
$response = call_user_func([$controller, $handler[1]]);
if ($response instanceof IContent) {
header('Content-Type: ' . $response->getContentType() . '; charset=UTF-8');
$response->render();
} elseif ($response instanceof IRedirect) {
header('Location: ' . $response->getUrl(), true, $response->getHttpCode());
} else {
$this->render404();
}
}
private function redirectToLogin(): void
{
$this->request->session()->set('redirect_after_login', $this->rawUrl);
$response = new Redirect($this->routeCollection->getRoute($this->appConfig['loginRouteId'])->generateLink(), IRedirect::TEMPORARY);
header('Location: ' . $response->getUrl(), true, $response->getHttpCode());
}
private function renderAntiCsrfError(): void
{
$content = new JsonContent($this->appConfig['antiCsrfTokenErrorResponse']);
header('Content-Type: text/html; charset=UTF-8', true, 403);
$content->render();
}
private function render404(): void
{
$content = new HtmlContent($this->appConfig['error404View']);
header('Content-Type: text/html; charset=UTF-8', true, 404);
$content->render();
}
}