From 719f819cfab84dd27d0a51e0f2c3248f4dffbb53 Mon Sep 17 00:00:00 2001 From: Daniel Ronkainen Date: Sun, 22 Mar 2026 14:14:19 +0100 Subject: [PATCH] feat: add callable that is passed to controller request handler --- src/ControllerRequestHandler.php | 209 ++++++++++++++++--------------- src/Kernel.php | 110 ++++++++-------- 2 files changed, 163 insertions(+), 156 deletions(-) diff --git a/src/ControllerRequestHandler.php b/src/ControllerRequestHandler.php index e66477a..e6f17a8 100644 --- a/src/ControllerRequestHandler.php +++ b/src/ControllerRequestHandler.php @@ -4,6 +4,7 @@ namespace MaplePHP\Emitron; +use Closure; use MaplePHP\Container\Reflection; use MaplePHP\Http\StreamFactory; use Psr\Http\Message\ResponseFactoryInterface; @@ -14,105 +15,111 @@ final class ControllerRequestHandler implements RequestHandlerInterface { - public function __construct( - private readonly ResponseFactoryInterface $factory, - private readonly array|\Closure $controller - ) {} - - public function handle(ServerRequestInterface $request): ResponseInterface - { - $response = $this->factory->createResponse(); - - $this->appendInterfaces([ - "ResponseInterface" => $response, - ]); - - $controller = $this->controller; - if(is_callable($controller)) { - return $controller($request, $response); - } - - if (!isset($controller[1])) { - $controller[1] = '__invoke'; - } - - if (count($controller) !== 2) { - $response->getBody()->write("ERROR: Invalid controller handler.\n"); - return $response; - } - - [$class, $method] = $controller; - - if (!method_exists($class, $method)) { - $response->getBody()->write("ERROR: Could not load Controller {$class}::{$method}().\n"); - return $response; - } - - // Your DI wiring - $reflect = new Reflection($class); - $classInst = $reflect->dependencyInjector(); - - // This should INVOKE the method and return its result (ResponseInterface or something else) - $result = $reflect->dependencyInjector($classInst, $method); - - return $this->createResponse($response, $result); - } - - - /** - * Will create a PSR valid Response instance form mixed result - * - * @param ResponseInterface $response - * @param mixed $result - * @return ResponseInterface - */ - protected function createResponse(ResponseInterface $response, mixed $result): ResponseInterface - { - if ($result instanceof ResponseInterface) { - return $result; - } - - if($result instanceof StreamInterface) { - return $response->withBody($result); - } - - if(is_array($result) || is_object($result)) { - return $this->createStream($response, json_encode($result, JSON_UNESCAPED_UNICODE)) - ->withHeader("Content-Type", "application/json"); - } - - if(is_string($result) || is_numeric($result)) { - return $this->createStream($response, $result); - } - return $response; - } - - /** - * A helper method to create a new stream instance - * - * @param ResponseInterface $response - * @param mixed $result - * @return ResponseInterface - */ - protected function createStream(ResponseInterface $response, mixed $result): ResponseInterface - { - $streamFactory = new StreamFactory(); - $stream = $streamFactory->createStream($result); - return $response->withBody($stream); - - } - - /** - * Append interface helper method - * - * @param array $bindings - * @return void - */ - protected function appendInterfaces(array $bindings) - { - Reflection::interfaceFactory(function (string $className) use ($bindings) { - return $bindings[$className] ?? null; - }); - } - + public function __construct( + private readonly ResponseFactoryInterface $factory, + private readonly array|Closure $controller, + private readonly ?Closure $call = null + ) + { + } + + public function handle(ServerRequestInterface $request): ResponseInterface + { + $response = $this->factory->createResponse(); + + $this->appendInterfaces([ + "ResponseInterface" => $response, + ]); + + $controller = $this->controller; + if (is_callable($controller)) { + return $controller($request, $response); + } + + if (!isset($controller[1])) { + $controller[1] = '__invoke'; + } + + if (count($controller) !== 2) { + $response->getBody()->write("ERROR: Invalid controller handler.\n"); + return $response; + } + + [$class, $method] = $controller; + + if (!method_exists($class, $method)) { + $response->getBody()->write("ERROR: Could not load Controller {$class}::{$method}().\n"); + return $response; + } + + // Your DI wiring + $reflect = new Reflection($class); + $classInst = $reflect->dependencyInjector(); + + $call = $this->call; + if ($call !== null) { + $call($classInst, $response); + } + // This should INVOKE the method and return its result (ResponseInterface or something else) + $result = $reflect->dependencyInjector($classInst, $method); + + return $this->createResponse($response, $result); + } + + + /** + * Will create a PSR valid Response instance form mixed result + * + * @param ResponseInterface $response + * @param mixed $result + * @return ResponseInterface + */ + protected function createResponse(ResponseInterface $response, mixed $result): ResponseInterface + { + if ($result instanceof ResponseInterface) { + return $result; + } + + if ($result instanceof StreamInterface) { + return $response->withBody($result); + } + + if (is_array($result) || is_object($result)) { + return $this->createStream($response, json_encode($result, JSON_UNESCAPED_UNICODE)) + ->withHeader("Content-Type", "application/json"); + } + + if (is_string($result) || is_numeric($result)) { + return $this->createStream($response, $result); + } + return $response; + } + + /** + * A helper method to create a new stream instance + * + * @param ResponseInterface $response + * @param mixed $result + * @return ResponseInterface + */ + protected function createStream(ResponseInterface $response, mixed $result): ResponseInterface + { + $streamFactory = new StreamFactory(); + $stream = $streamFactory->createStream($result); + return $response->withBody($stream); + + } + + /** + * Append interface helper method + * + * @param array $bindings + * @return void + */ + protected function appendInterfaces(array $bindings) + { + Reflection::interfaceFactory(function (string $className) use ($bindings) { + return $bindings[$className] ?? null; + }); + } } \ No newline at end of file diff --git a/src/Kernel.php b/src/Kernel.php index c2f079e..7c9ae2a 100644 --- a/src/Kernel.php +++ b/src/Kernel.php @@ -23,69 +23,69 @@ class Kernel extends AbstractKernel { - /** - * Run the emitter and init all routes, middlewares and configs - * - * @param ServerRequestInterface $request - * @param StreamInterface|null $stream - * @return void - */ - public function run(ServerRequestInterface $request, ?StreamInterface $stream = null): void - { - $this->dispatchConfig->getRouter()->dispatch(function ($data, $args, $middlewares) use ($request, $stream) { + /** + * Run the emitter and init all routes, middlewares and configs + * + * @param ServerRequestInterface $request + * @param StreamInterface|null $stream + * @param callable|null $call + * @return void + */ + public function run(ServerRequestInterface $request, ?StreamInterface $stream = null, ?callable $call = null): void + { + $this->dispatchConfig->getRouter()->dispatch(function ($data, $args, $middlewares) use ($request, $stream, $call) { - if($args === null) { - $args = $request->getCliArgs(); - } + if ($args === null) { + $args = $request->getCliArgs(); + } - $parts = isset($data[2]) && is_array($data[2]) ? $data[2] : []; - $dispatchCode = (int)($data[0] ?? DispatchCodes::FOUND->value); + $parts = isset($data[2]) && is_array($data[2]) ? $data[2] : []; + $dispatchCode = (int)($data[0] ?? DispatchCodes::FOUND->value); - if($dispatchCode !== DispatchCodes::FOUND->value) { - $data['handler'] = function (ServerRequestInterface $req, ResponseInterface $res): ResponseInterface - { - return $res->withStatus(404); - }; - } - //$dispatchCode = $data[0] ?? RouterDispatcher::FOUND; - [$data, $args, $middlewares] = $this->reMap($data, $args, $middlewares); + if ($dispatchCode !== DispatchCodes::FOUND->value) { + $data['handler'] = function (ServerRequestInterface $req, ResponseInterface $res): ResponseInterface { + return $res->withStatus(404); + }; + } + //$dispatchCode = $data[0] ?? RouterDispatcher::FOUND; + [$data, $args, $middlewares] = $this->reMap($data, $args, $middlewares); - $this->container->set("request", $request); - $this->container->set("args", $args); - $this->container->set("configuration", $this->getDispatchConfig()); + $this->container->set("request", $request); + $this->container->set("args", $args); + $this->container->set("configuration", $this->getDispatchConfig()); - $bodyStream = $this->getBody($stream); - $factory = new ResponseFactory($bodyStream); - $finalHandler = new ControllerRequestHandler($factory, $data['handler'] ?? []); + $bodyStream = $this->getBody($stream); + $factory = new ResponseFactory($bodyStream); + $finalHandler = new ControllerRequestHandler($factory, $data['handler'] ?? [], $call); $path = new Path($parts, $request); - - $response = $this->initRequestHandler( - request: $request, - stream: $bodyStream, + $response = $this->initRequestHandler( + request: $request, + stream: $bodyStream, path: $path, - finalHandler: $finalHandler, - middlewares: $middlewares - ); - $this->createEmitter()->emit($response, $request); - }); - } + finalHandler: $finalHandler, + middlewares: $middlewares + ); + + $this->createEmitter()->emit($response, $request); + }); + } - function reMap($data, $args, $middlewares) - { - if (isset($data[1]) && $middlewares instanceof ServerRequestInterface) { - $item = $data[1]; - return [ - ["handler" => $item['controller']], ($args == null ? $_REQUEST : $args), ($item['data'] ?? []) - ]; - } - if (!is_array($middlewares)) { - $middlewares = []; - } - if (!is_array($args)) { - $args = []; - } - return [$data, $args, $middlewares]; - } + function reMap($data, $args, $middlewares) + { + if (isset($data[1]) && $middlewares instanceof ServerRequestInterface) { + $item = $data[1]; + return [ + ["handler" => $item['controller']], ($args == null ? $_REQUEST : $args), ($item['data'] ?? []) + ]; + } + if (!is_array($middlewares)) { + $middlewares = []; + } + if (!is_array($args)) { + $args = []; + } + return [$data, $args, $middlewares]; + } } \ No newline at end of file