Commit c3bd6601 authored by Oliver Bartsch's avatar Oliver Bartsch
Browse files

Add factory for RouteResultArguments

parent 7bac7c26
......@@ -42,8 +42,7 @@ final class RestRouteDispatcher implements MiddlewareInterface
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
if ($this->isApiRequest($request->getUri()->getPath())) {
// @todo Might need need some further TSFE initialization here
if ($this->isApiRequest($request->getUri()->getPath())) {
return $this->routeHandler->handle($request);
}
......
......@@ -23,8 +23,6 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
*/
final class ApiResponseFactory
{
private const DEFAULT_RESPONSE_TYPE = 'application/json';
protected $availableResponseTypes;
public function __construct(ExtensionConfiguration $extensionConfiguration)
......@@ -88,8 +86,7 @@ final class ApiResponseFactory
protected function initializeResponse(ServerRequestInterface $request): ResponseInterface
{
$types = $request->getHeader('accept')
?: $request->getHeader('content-type')
?: [self::DEFAULT_RESPONSE_TYPE];
?: $request->getHeader('content-type');
$type = (string)reset($types);
......
......@@ -18,6 +18,7 @@ use Psr\Http\Server\RequestHandlerInterface;
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use T3o\Ter\Exception\RequiredArgumentMissingException;
use T3o\Ter\Exception\RequiredBodyMissingException;
use T3o\Ter\Rest\Response\ApiResponseFactory;
/**
......@@ -56,7 +57,7 @@ final class RouteHandler implements RequestHandlerInterface
} catch (MethodNotAllowedException $e) {
$message = 'The method ' . $request->getMethod() . ' is not allowed.';
return $this->apiResponseFactory->createErrorResponseForRequest($request, 1600994273, $message, 405);
} catch (RequiredArgumentMissingException $e) {
} catch (RequiredArgumentMissingException|RequiredBodyMissingException $e) {
return $this->apiResponseFactory->createErrorResponseForRequest($request, 1600996241, $e->getMessage(), 400);
} catch (ResourceNotFoundException|\OutOfRangeException|\InvalidArgumentException $e) {
return $this->apiResponseFactory->createErrorResponseForRequest($request, 1601289397, $e->getMessage());
......
......@@ -13,12 +13,10 @@ namespace T3o\Ter\Rest;
*/
use Psr\Http\Message\ServerRequestInterface;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use T3o\Ter\Exception\RequiredArgumentMissingException;
use T3o\Ter\Exception\RequiredBodyMissingException;
use T3o\Ter\Rest\RouteArgument\RouteArgumentFactory;
use TYPO3\CMS\Core\Routing\RouteResultInterface;
/**
......@@ -33,14 +31,14 @@ use TYPO3\CMS\Core\Routing\RouteResultInterface;
final class RouteResolver
{
protected RouteConfiguration $routeConfiguration;
protected RouteArgumentFactory $routeArgumentFactory;
protected RouteResultArgumentsFactory $routeResultArgumentsFactory;
public function __construct(
RouteConfiguration $routeConfiguration,
RouteArgumentFactory $routeArgumentFactory
RouteResultArgumentsFactory $routeResultArgumentsFactory
) {
$this->routeConfiguration = $routeConfiguration;
$this->routeArgumentFactory = $routeArgumentFactory;
$this->routeResultArgumentsFactory = $routeResultArgumentsFactory;
}
public function resolve(ServerRequestInterface $request): RouteResultInterface
......@@ -50,20 +48,6 @@ final class RouteResolver
$this->getRequestContext($request)
))->match($this->routeConfiguration->getPath());
if (!($resultParameters['_route'] ?? false)) {
throw new ResourceNotFoundException('No resource found for the given route.', 1600994133);
}
if (!($resultParameters['_controller'] ?? false)) {
throw new \InvalidArgumentException('No handler found for the given route.', 1600994145);
}
$routeResultArguments = new RouteResultArguments(
$resultParameters['_route'],
$resultParameters['_controller'],
$resultParameters['_middlewares'] ?? [],
);
$arguments = array_merge(
array_filter($resultParameters, static function ($_, $k) {
return strpos($k, '_') !== 0;
......@@ -71,49 +55,17 @@ final class RouteResolver
$request->getQueryParams()
);
foreach ($arguments as $name => $value) {
$configuration = $this->routeConfiguration->getParameterConfiguration($name);
if ($configuration !== []) {
$routeResultArguments->addRouteArgument($this->routeArgumentFactory->create($name, $configuration, $value));
}
}
$endpointConfiguration = $this->routeConfiguration->getEndpointConfiguration(
$routeResultArguments->offsetGet('operationId')
);
$endpointConfiguration = $this->routeConfiguration->getEndpointConfiguration($resultParameters['_route'] ?? '');
if (isset($endpointConfiguration['parameters']) && is_array($endpointConfiguration['parameters'])) {
foreach ($endpointConfiguration['parameters'] as $parameter) {
if ((bool)($parameter['required'] ?? false)
&& !$routeResultArguments->hasRouteArgument($parameter['name'])
) {
throw new RequiredArgumentMissingException(
sprintf(
'%s argument %s is required but is missing in the request.',
ucfirst($parameter['in']),
$parameter['name']
),
1601369655
);
}
}
$this->validateParameters($endpointConfiguration['parameters'], $arguments);
}
if (isset($endpointConfiguration['requestBody']) && is_array($endpointConfiguration['requestBody'])) {
foreach ($endpointConfiguration['requestBody'] as $key => $requestBody) {
if ($key === '$ref') {
$requestBody = $this->routeConfiguration->getParameterConfigurationByReference($requestBody);
}
if ((bool)($requestBody['required'] ?? false) && $request->getParsedBody() === null) {
throw new RequiredBodyMissingException(
sprintf('Required request body for %s is missing in the request.', $requestBody['reference']),
1601369655
);
}
}
$this->validateRequestBody($endpointConfiguration['requestBody'], $request->getParsedBody());
}
return $routeResultArguments;
return $this->routeResultArgumentsFactory->create($resultParameters, $arguments);
}
protected function getRequestContext(ServerRequestInterface $request): RequestContext
......@@ -130,4 +82,35 @@ final class RouteResolver
$uri->getQuery()
);
}
protected function validateParameters(array $parameters, array $arguments): void
{
foreach ($parameters as $parameter) {
if ((bool)($parameter['required'] ?? false) && !isset($arguments[$parameter['name']])) {
throw new RequiredArgumentMissingException(
sprintf(
'%s argument %s is required but is missing in the request.',
ucfirst($parameter['in']),
$parameter['name']
),
1601369655
);
}
}
}
protected function validateRequestBody(array $requestBody, $parsedBody = null): void
{
foreach ($requestBody as $key => $content) {
if ($key === '$ref') {
$content = $this->routeConfiguration->getParameterConfigurationByReference($content);
}
if ((bool)($content['required'] ?? false) && $parsedBody === null) {
throw new RequiredBodyMissingException(
sprintf('Required request body for %s is missing in the request.', $content['reference']),
1601369734
);
}
}
}
}
<?php
declare(strict_types = 1);
namespace T3o\Ter\Rest;
/*
* This file is part of TYPO3 CMS-extension "ter", created by Oliver Bartsch.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*/
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use T3o\Ter\Rest\RouteArgument\RouteArgumentFactory;
use TYPO3\CMS\Core\Routing\RouteResultInterface;
/**
* Create a RouteResultArguments object
*
* @see RouteResultArguments
*/
final class RouteResultArgumentsFactory
{
protected RouteConfiguration $routeConfiguration;
protected RouteArgumentFactory $routeArgumentFactory;
public function __construct(
RouteConfiguration $routeConfiguration,
RouteArgumentFactory $routeArgumentFactory
) {
$this->routeConfiguration = $routeConfiguration;
$this->routeArgumentFactory = $routeArgumentFactory;
}
public function create(array $resultParameters, array $arguments): RouteResultInterface
{
if (!($resultParameters['_route'] ?? false)) {
throw new ResourceNotFoundException('No resource found for the given route.', 1600994133);
}
if (!($resultParameters['_controller'] ?? false)) {
throw new \InvalidArgumentException('No handler found for the given route.', 1600994145);
}
$routeResultArguments = new RouteResultArguments(
$resultParameters['_route'],
$resultParameters['_controller'],
$resultParameters['_middlewares'] ?? [],
);
foreach ($arguments as $name => $value) {
$configuration = $this->routeConfiguration->getParameterConfiguration($name);
if ($configuration !== []) {
$routeResultArguments->addRouteArgument(
$this->routeArgumentFactory->create($name, $configuration, $value)
);
}
}
return $routeResultArguments;
}
}
......@@ -93,6 +93,7 @@ return [
'Object' => \T3o\Ter\Rest\RouteArgument\ObjectArgument::class
],
'responseTypes' => [
'*/*' => \TYPO3\CMS\Core\Http\JsonResponse::class,
'application/json' => \TYPO3\CMS\Core\Http\JsonResponse::class
]
]
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment