724 * @throws \ReflectionException If there is an issue with reflection.
725 * @throws \Exception
726 * @return Response
727 */
728 public function resolve(Application $app, Request $request): Response
729 {
730 $callback = $this->getCallback($request);
731
732 if (!$callback) {
733 throw new \Exception("The Requested Route [{$request->uri()}] Not Found.", 404);
734 }
735
736 $currentMiddleware = $this->getCurrentRouteMiddleware($request);
737
738 if ($currentMiddleware) {
739 $this->applyRouteMiddleware($request, $app, $currentMiddleware);
740 }
741
742 $routeParams = $request->getRouteParams();
743
744 $handler = function ($request) use ($callback, $app, $routeParams) {
745 $result = $this->resolveAction($callback, $app, $routeParams);
746 $response = app('response');
747 $response->setOriginal($result);
748 if (!($result instanceof Response)) {
749 return $this->getResolutionResponse($request, $result, $response);
750 }
751 return $result;
752 };
753
754 $response = $this->handle($request, $handler);
755
756 return $response;
757 }
758
759 /**
760 * Handle attributes based middleware defination
761 *
762 * @param array $callback
763 * @return void
764 */
765 protected function processControllerMiddleware(array|string $callback): void
766 {
767 if (is_string($callback)) {
768 $controllerClass = $callback;
769 $actionMethod = "__invoke";
770 } else {
771 [$controllerClass, $actionMethod] = $callback;
772 }
773
774 $reflector = new \ReflectionClass($controllerClass);
775
776 // Process middleware defined at the class level
777 // if any are present
778 $classMiddlewareAttributes = $reflector->getAttributes(Middleware::class);
779 $this->processAttributesMiddlewares($classMiddlewareAttributes);
780
781 // Process middleware defined at the method level
782 // if any are present
783 if ($reflector->hasMethod($actionMethod)) {
784 $method = $reflector->getMethod($actionMethod);
785 $methodMiddlewareAttributes = $method->getAttributes(Middleware::class);
786 $this->processAttributesMiddlewares($methodMiddlewareAttributes);
787 }
788 }
789
790 /**
791 * Resolve form request class
792 *
793 * This method handles the resolution and initialization of form request validation classes.
794 * It ensures the class is properly bound in the container and triggers validation if needed.
795 *
796 * @param Application $app The application instance
797 * @param string $typeName The class name to resolve
798 * @return mixed
799 */
800 private function resolveFormRequestValidationClass($app, $typeName): mixed
801 {
802 if (!$app->has($typeName)) {
803 if (is_subclass_of($typeName, ValidatesWhenResolved::class)) {
804 $app->singleton($typeName, fn() => new $typeName(app('request')));
805 } else {
806 $app->singleton($typeName, $typeName);
807 }
808 }
809
810 $resolvedInstance = app($typeName);
811
812 if ($resolvedInstance instanceof ValidatesWhenResolved) {
813 $resolvedInstance->resolvedFormRequestValidation();
814 }
815
816 return $resolvedInstance;
817 }
818
819 /**
820 * Converts mixed data into a JSON response.
821 * - Objects (any class) are JSON-encoded.
822 * - Arrays, Collections, Models, and Builders are JSON-encoded.
823 * - Non-JSON types (strings, numbers, etc.) are returned as-is.
824 * @param $request
825 * @param $result
826 * @param mixed $response
827 * @return Response
828 */
829 private function getResolutionResponse($request, $result, $response): Response
830 {
831 if ($this->shouldBeJson($result)) {
832 $request->setRequestFormat('json');
833 $response->headers->set('Content-Type', 'application/json');
834 $result = $this->convertToSerializable($result);