container = $container ?? $this->buildContainer(); $this->dispatcher = $dispatcher ?? $this->buildDispatcher(); } public function container(): Container { return $this->container; } public function dispatcher(): Dispatcher { return $this->dispatcher; } public function handle(ServerRequest $request): ResponseInterface { $psr17 = new Psr17Factory(); $middleware = [ new Middleware\ProblemDetailsMiddleware( \Phred\Support\Config::get('APP_DEBUG', 'false') === 'true', null, null, filter_var(\Phred\Support\Config::get('API_PROBLEM_DETAILS', 'true'), FILTER_VALIDATE_BOOLEAN) ), new Middleware\ContentNegotiationMiddleware(), new Middleware\RoutingMiddleware($this->dispatcher, $psr17), new Middleware\DispatchMiddleware($psr17), ]; $relay = new Relay($middleware); return $relay->handle($request); } private function buildContainer(): Container { $builder = new ContainerBuilder(); // Add definitions/bindings here as needed. $builder->addDefinitions([ \Phred\Support\Contracts\ConfigInterface::class => \DI\autowire(\Phred\Support\DefaultConfig::class), \Phred\Http\Contracts\ErrorFormatNegotiatorInterface::class => \DI\autowire(\Phred\Http\Support\DefaultErrorFormatNegotiator::class), \Phred\Http\Contracts\RequestIdProviderInterface::class => \DI\autowire(\Phred\Http\Support\DefaultRequestIdProvider::class), \Phred\Http\Contracts\ExceptionToStatusMapperInterface::class => \DI\autowire(\Phred\Http\Support\DefaultExceptionToStatusMapper::class), \Phred\Http\Contracts\ApiResponseFactoryInterface::class => \DI\autowire(\Phred\Http\Responses\DelegatingApiResponseFactory::class), \Phred\Http\Responses\RestResponseFactory::class => \DI\autowire(\Phred\Http\Responses\RestResponseFactory::class), \Phred\Http\Responses\JsonApiResponseFactory::class => \DI\autowire(\Phred\Http\Responses\JsonApiResponseFactory::class), ]); return $builder->build(); } private function buildDispatcher(): Dispatcher { $routesPath = dirname(__DIR__, 2) . '/routes'; $collector = static function (RouteCollector $r) use ($routesPath): void { // Load user-defined routes if present $router = new Router($r); foreach (['web.php', 'api.php'] as $file) { $path = $routesPath . '/' . $file; if (is_file($path)) { /** @noinspection PhpIncludeInspection */ (static function ($router) use ($path) { require $path; })($router); } } // Ensure default demo routes exist for acceptance/demo $r->addRoute('GET', '/_phred/health', [Controllers\HealthController::class, '__invoke']); $r->addRoute('GET', '/_phred/format', [Controllers\FormatController::class, '__invoke']); }; return simpleDispatcher($collector); } }