Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/DispatchContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,9 @@ private function resetHandlerState(): void
{
foreach ($this->handlers as $handler) {
if ($handler instanceof ErrorHandler) {
$handler->errors = [];
$handler->clearErrors();
} elseif ($handler instanceof ExceptionHandler) {
$handler->exception = null;
$handler->clearException();
}
}
}
Expand All @@ -277,7 +277,7 @@ static function (
string $errfile = '',
int $errline = 0,
) use ($handler): bool {
$handler->errors[] = [$errno, $errstr, $errfile, $errline];
$handler->addError($errno, $errstr, $errfile, $errline);

return true;
},
Expand All @@ -291,7 +291,7 @@ static function (
private function forwardCollectedErrors(): ResponseInterface|null
{
foreach ($this->handlers as $handler) {
if ($handler instanceof ErrorHandler && $handler->errors) {
if ($handler instanceof ErrorHandler && $handler->hasErrors()) {
return $this->forward($handler);
}
}
Expand All @@ -306,8 +306,8 @@ private function catchExceptions(Throwable $e): ResponseInterface|null
continue;
}

if (is_a($e, $handler->class)) {
$handler->exception = $e;
if ($handler->matches($e)) {
$handler->capture($e);

return $this->forward($handler);
}
Expand Down
25 changes: 19 additions & 6 deletions src/Handlers/ErrorHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,33 @@

namespace Respect\Rest\Handlers;

use Respect\Fluent\Factories\NamespaceLookup;
use Respect\Rest\DispatchContext;
use Respect\Rest\Routes\Callback;

final class ErrorHandler extends Callback
{
/** @var callable */
public $callback;

/** @var array<int, array<int, mixed>> */
public array $errors = [];
private array $errors = [];

public function __construct(NamespaceLookup $routineLookup, callable $callback)
{
parent::__construct($routineLookup, 'ANY', '^$', $callback);
}

public function addError(int $errno, string $errstr, string $errfile, int $errline): void
{
$this->errors[] = [$errno, $errstr, $errfile, $errline];
}

public function hasErrors(): bool
{
return $this->errors !== [];
}

public function __construct(callable $callback)
public function clearErrors(): void
{
parent::__construct('ANY', '^$', $callback);
$this->errors = [];
}

/** @param array<int, mixed> $params */
Expand Down
25 changes: 20 additions & 5 deletions src/Handlers/ExceptionHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,35 @@

namespace Respect\Rest\Handlers;

use Respect\Fluent\Factories\NamespaceLookup;
use Respect\Rest\DispatchContext;
use Respect\Rest\Routes\Callback;
use Throwable;

use function is_a;

final class ExceptionHandler extends Callback
{
/** @var callable */
public $callback;
private Throwable|null $exception = null;

public Throwable|null $exception = null;
public function __construct(NamespaceLookup $routineLookup, public private(set) string $class, callable $callback)
{
parent::__construct($routineLookup, 'ANY', '^$', $callback);
}

public function matches(Throwable $e): bool
{
return is_a($e, $this->class);
}

public function capture(Throwable $e): void
{
$this->exception = $e;
}

public function __construct(public string $class, callable $callback)
public function clearException(): void
{
parent::__construct('ANY', '^$', $callback);
$this->exception = null;
}

/** @param array<int, mixed> $params */
Expand Down
13 changes: 7 additions & 6 deletions src/Handlers/StatusHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@

namespace Respect\Rest\Handlers;

use Respect\Fluent\Factories\NamespaceLookup;
use Respect\Rest\Routes\Callback;

final class StatusHandler extends Callback
{
/** @var callable */
public $callback;

public function __construct(public readonly int|null $statusCode, callable $callback)
{
parent::__construct('ANY', '^$', $callback);
public function __construct(
NamespaceLookup $routineLookup,
public readonly int|null $statusCode,
callable $callback,
) {
parent::__construct($routineLookup, 'ANY', '^$', $callback);
}
}
10 changes: 4 additions & 6 deletions src/Responder.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,6 @@ public function finalize(
): ResponseInterface {
$response = $this->normalize($result);

if ($responseDraft !== null) {
if ($statusOverridden) {
$response = $response->withStatus($responseDraft->getStatusCode(), $responseDraft->getReasonPhrase());
}
}

foreach ($defaultHeaders as $name => $value) {
if ($response->hasHeader($name)) {
continue;
Expand All @@ -75,6 +69,10 @@ public function finalize(
}

if ($responseDraft !== null) {
if ($statusOverridden) {
$response = $response->withStatus($responseDraft->getStatusCode(), $responseDraft->getReasonPhrase());
}

foreach ($responseDraft->getHeaders() as $name => $values) {
if (!isset($appendedHeaderNames[strtolower($name)])) {
$response = $response->withHeader($name, $values);
Expand Down
54 changes: 19 additions & 35 deletions src/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ final class Router implements MiddlewareInterface, RequestHandlerInterface, Rout
public function __construct(
protected string $basePath,
private ResponseFactoryInterface&StreamFactoryInterface $factory,
NamespaceLookup|null $routineLookup = null,
) {
$this->basePath = rtrim($basePath, '/');
$this->routineLookup = new NamespaceLookup(
$this->routineLookup = $routineLookup ?? new NamespaceLookup(
new Ucfirst(),
Routinable::class,
'Respect\\Rest\\Routines',
Expand All @@ -81,18 +82,10 @@ public function always(string $routineName, mixed ...$params): static
return $this;
}

public function withRoutineNamespace(string $namespace): static
{
$this->routineLookup = $this->routineLookup->withNamespace($namespace);

return $this;
}

public function appendRoute(AbstractRoute $route): static
{
$this->routes[] = $route;
$route->basePath = $this->basePath;
$route->setRoutineLookup($this->routineLookup);
$route->setBasePath($this->basePath);

foreach ($this->globalRoutines as $routine) {
$route->appendRoutine($routine);
Expand All @@ -106,7 +99,6 @@ public function appendRoute(AbstractRoute $route): static
public function appendHandler(AbstractRoute $handler): static
{
$this->handlers[] = $handler;
$handler->setRoutineLookup($this->routineLookup);

foreach ($this->globalRoutines as $routine) {
$handler->appendRoutine($routine);
Expand All @@ -122,7 +114,7 @@ public function callbackRoute(
callable $callback,
array $arguments = [],
): Routes\Callback {
$route = new Routes\Callback($method, $path, $callback, $arguments);
$route = new Routes\Callback($this->routineLookup, $method, $path, $callback, $arguments);
$this->appendRoute($route);

return $route;
Expand All @@ -131,7 +123,7 @@ public function callbackRoute(
/** @param array<int, mixed> $arguments */
public function classRoute(string $method, string $path, string $class, array $arguments = []): Routes\ClassName
{
$route = new Routes\ClassName($method, $path, $class, $arguments);
$route = new Routes\ClassName($this->routineLookup, $method, $path, $class, $arguments);
$this->appendRoute($route);

return $route;
Expand All @@ -151,10 +143,6 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
{
$context = $this->dispatch($request);

if ($context->route === null && !$context->hasPreparedResponse()) {
return $handler->handle($request);
}

if ($context->route === null) {
$response = $context->response();
if ($response !== null && $response->getStatusCode() === 404) {
Expand Down Expand Up @@ -185,23 +173,23 @@ public function dispatchContext(DispatchContext $context): DispatchContext

public function onException(string $className, callable $callback): Handlers\ExceptionHandler
{
$handler = new Handlers\ExceptionHandler($className, $callback);
$handler = new Handlers\ExceptionHandler($this->routineLookup, $className, $callback);
$this->appendHandler($handler);

return $handler;
}

public function onError(callable $callback): Handlers\ErrorHandler
{
$handler = new Handlers\ErrorHandler($callback);
$handler = new Handlers\ErrorHandler($this->routineLookup, $callback);
$this->appendHandler($handler);

return $handler;
}

public function onStatus(int|null $statusCode, callable $callback): Handlers\StatusHandler
{
$handler = new Handlers\StatusHandler($statusCode, $callback);
$handler = new Handlers\StatusHandler($this->routineLookup, $statusCode, $callback);
$this->appendHandler($handler);

return $handler;
Expand All @@ -215,23 +203,23 @@ public function getHandlers(): array

public function factoryRoute(string $method, string $path, string $className, callable $factory): Routes\Factory
{
$route = new Routes\Factory($method, $path, $className, $factory);
$route = new Routes\Factory($this->routineLookup, $method, $path, $className, $factory);
$this->appendRoute($route);

return $route;
}

public function instanceRoute(string $method, string $path, object $instance): Routes\Instance
{
$route = new Routes\Instance($method, $path, $instance);
$route = new Routes\Instance($this->routineLookup, $method, $path, $instance);
$this->appendRoute($route);

return $route;
}

public function staticRoute(string $method, string $path, mixed $staticValue): Routes\StaticValue
{
$route = new Routes\StaticValue($method, $path, $staticValue);
$route = new Routes\StaticValue($this->routineLookup, $method, $path, $staticValue);
$this->appendRoute($route);

return $route;
Expand All @@ -256,11 +244,6 @@ public function dispatchEngine(): DispatchEngine
);
}

public static function compareOcurrences(string $patternA, string $patternB, string $sub): bool
{
return substr_count($patternA, $sub) < substr_count($patternB, $sub);
}

protected function sortRoutesByComplexity(): void
{
usort(
Expand All @@ -273,7 +256,7 @@ static function (AbstractRoute $a, AbstractRoute $b): int {
return 0;
}

$slashCount = Router::compareOcurrences($pa, $pb, '/');
$slashCount = Router::compareOccurrences($pa, $pb, '/');

$aCatchall = preg_match('#/\*\*$#', $pa);
$bCatchall = preg_match('#/\*\*$#', $pb);
Expand All @@ -285,7 +268,7 @@ static function (AbstractRoute $a, AbstractRoute $b): int {
return $slashCount ? 1 : -1;
}

if (Router::compareOcurrences($pa, $pb, AbstractRoute::PARAM_IDENTIFIER)) {
if (Router::compareOccurrences($pa, $pb, AbstractRoute::PARAM_IDENTIFIER)) {
return -1;
}

Expand All @@ -294,6 +277,11 @@ static function (AbstractRoute $a, AbstractRoute $b): int {
);
}

private static function compareOccurrences(string $patternA, string $patternB, string $sub): bool
{
return substr_count($patternA, $sub) < substr_count($patternB, $sub);
}

/** @param array<int, mixed> $args */
public function __call(string $method, array $args): AbstractRoute
{
Expand All @@ -315,11 +303,7 @@ public function __call(string $method, array $args): AbstractRoute
}

if (is_callable($routeTarget)) {
if (!isset($args[2])) {
return $this->callbackRoute($method, $path, $routeTarget);
}

return $this->callbackRoute($method, $path, $routeTarget, $args[2]);
return $this->callbackRoute($method, $path, $routeTarget, $args[2] ?? []);
}

if ($routeTarget instanceof Routable) {
Expand Down
23 changes: 12 additions & 11 deletions src/Routes/AbstractRoute.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,21 +65,22 @@ abstract class AbstractRoute
public const string REGEX_OPTIONAL_PARAM = '(?:/([^/]+))?';
public const string REGEX_INVALID_OPTIONAL_PARAM = '#\(\?\:/\(\[\^/\]\+\)\)\?/#';

public string $method = '';
public private(set) string $method = '';

public string $regexForMatch = '';
public private(set) string $regexForMatch = '';

public string $regexForReplace = '';
public private(set) string $regexForReplace = '';

/** @var array<string, Routinable> */
public array $routines = [];
public private(set) array $routines = [];

public string|null $basePath = null;
public private(set) string|null $basePath = null;

private NamespaceLookup $routineLookup;

public function __construct(string $method, public string $pattern = '')
{
public function __construct(
private NamespaceLookup $routineLookup,
string $method,
public string $pattern,
) {
$this->method = strtoupper($method);

[$this->regexForMatch, $this->regexForReplace]
Expand Down Expand Up @@ -147,9 +148,9 @@ public function appendRoutine(Routinable $routine): static
return $this;
}

public function setRoutineLookup(NamespaceLookup $lookup): void
public function setBasePath(string|null $basePath): void
{
$this->routineLookup = $lookup;
$this->basePath = $basePath;
}

public function createUri(mixed ...$params): string
Expand Down
Loading
Loading