injectableFactory = $injectableFactory; $this->classFinder = $classFinder; } public function process( string $controllerName, string $requestMethod, string $actionName, array $params, Request $request, Response $response ) { $controller = $this->createController($controllerName); if ($actionName == 'index') { $actionName = $controller::$defaultAction ?? 'index'; } $actionNameUcfirst = ucfirst($actionName); $actionMethodName = 'action' . $actionNameUcfirst; $fullActionMethodName = strtolower($requestMethod) . ucfirst($actionMethodName); if (method_exists($controller, $fullActionMethodName)) { $primaryActionMethodName = $fullActionMethodName; } else { $primaryActionMethodName = $actionMethodName; } if (!method_exists($controller, $primaryActionMethodName)) { throw new NotFound( "Action {$requestMethod} '{$actionName}' does not exist in controller '{$controllerName}'." ); } if ( $this->useShortParamList($controller, $primaryActionMethodName) ) { return $controller->$primaryActionMethodName($request, $response); } // Below is a legacy way. $data = $request->getParsedBody(); $beforeMethodName = 'before' . $actionNameUcfirst; if (method_exists($controller, $beforeMethodName)) { $controller->$beforeMethodName($params, $data, $request, $response); } $result = $controller->$primaryActionMethodName($params, $data, $request, $response); $afterMethodName = 'after' . $actionNameUcfirst; if (method_exists($controller, $afterMethodName)) { $controller->$afterMethodName($params, $data, $request, $response); } return $result; } protected function useShortParamList(object $controller, string $methodName) : bool { $class = new ReflectionClass($controller); $method = $class->getMethod($methodName); $params = $method->getParameters(); if (count($params) > 0) { $firstParamClass = $params[0]->getClass(); if ( $firstParamClass && ( $firstParamClass->getName() === Request::class || $firstParamClass->isSubclassOf(Request::class) ) ) { return true; } } return false; } protected function getControllerClassName(string $name) : string { $className = $this->classFinder->find('Controllers', $name); if (!$className) { throw new NotFound("Controller '{$name}' does not exist."); } if (!class_exists($className)) { throw new NotFound("Class not found for controller '{$name}'."); } return $className; } protected function createController(string $name) : object { return $this->injectableFactory->createWith($this->getControllerClassName($name), [ 'name' => $name, ]); } }