@@ -532,23 +532,13 @@ public function start(): void
532532 }
533533
534534 /**
535- * Match
535+ * Find the matching route for a request, or null if none match.
536536 *
537- * Find matching route given current user request
538- *
539- * @param bool $fresh If true, will not match any cached route
537+ * Stateless: re-runs the lookup every call, so callers always see a
538+ * result reflecting the request they passed in.
540539 */
541- public function match (Request $ request, bool $ fresh = true ): ?RouteMatch
540+ public function match (Request $ request ): ?RouteMatch
542541 {
543- $ context = $ this ->context ();
544-
545- if (!$ fresh && $ context ->has ('match ' )) {
546- $ cached = $ context ->get ('match ' );
547- if ($ cached instanceof RouteMatch) {
548- return $ cached ;
549- }
550- }
551-
552542 $ url = parse_url ($ request ->getURI (), PHP_URL_PATH );
553543 $ url = \is_string ($ url ) ? ($ url === '' ? '/ ' : $ url ) : '/ ' ;
554544 $ method = $ request ->getMethod ();
@@ -560,18 +550,73 @@ public function match(Request $request, bool $fresh = true): ?RouteMatch
560550 return null ;
561551 }
562552
563- $ context ->set ('match ' , fn () => $ match , []);
564553 $ route = $ match ->route ;
565- $ context ->set ('route ' , fn () => $ route , []);
554+ $ this -> context () ->set ('route ' , fn () => $ route , []);
566555
567556 return $ match ;
568557 }
569558
570559 /**
571- * Execute a matched route with middlewares and error handling.
560+ * Match the request to a registered route, then run its handler and hooks.
561+ *
562+ * Handles OPTIONS preflight (fires options hooks, returns) and HEAD
563+ * (matches as GET, suppresses the response body). If no route matches and
564+ * the method isn't OPTIONS, fires global error hooks with a 404 Exception.
572565 */
573- public function execute (RouteMatch $ match , Request $ request , Response $ response ): static
566+ public function execute (Request $ request , Response $ response ): static
574567 {
568+ $ method = $ request ->getMethod ();
569+
570+ if (self ::REQUEST_METHOD_HEAD === $ method ) {
571+ $ method = self ::REQUEST_METHOD_GET ;
572+ $ response ->disablePayload ();
573+ }
574+
575+ $ match = $ this ->match ($ request );
576+
577+ if (self ::REQUEST_METHOD_OPTIONS === $ method ) {
578+ $ groups = $ match ?->route->getGroups () ?? [];
579+
580+ try {
581+ foreach ($ groups as $ group ) {
582+ foreach (self ::$ options as $ option ) { // Group options hooks
583+ /** @var Hook $option */
584+ if (\in_array ($ group , $ option ->getGroups ())) {
585+ \call_user_func_array ($ option ->getAction (), $ this ->getArguments ($ option , [], $ request ->getParams ()));
586+ }
587+ }
588+ }
589+
590+ foreach (self ::$ options as $ option ) { // Global options hooks
591+ /** @var Hook $option */
592+ if (\in_array ('* ' , $ option ->getGroups ())) {
593+ \call_user_func_array ($ option ->getAction (), $ this ->getArguments ($ option , [], $ request ->getParams ()));
594+ }
595+ }
596+ } catch (\Throwable $ e ) {
597+ foreach (self ::$ errors as $ error ) { // Global error hooks
598+ /** @var Hook $error */
599+ if (\in_array ('* ' , $ error ->getGroups ())) {
600+ $ this ->context ()->set ('error ' , fn () => $ e , []);
601+ \call_user_func_array ($ error ->getAction (), $ this ->getArguments ($ error , [], $ request ->getParams ()));
602+ }
603+ }
604+ }
605+
606+ return $ this ;
607+ }
608+
609+ if ($ match === null ) {
610+ foreach (self ::$ errors as $ error ) {
611+ if (\in_array ('* ' , $ error ->getGroups ())) {
612+ $ this ->context ()->set ('error ' , fn () => new Exception ('Not Found ' , 404 ), []);
613+ \call_user_func_array ($ error ->getAction (), $ this ->getArguments ($ error , [], $ request ->getParams ()));
614+ }
615+ }
616+
617+ return $ this ;
618+ }
619+
575620 $ route = $ match ->route ;
576621 $ arguments = [];
577622 $ groups = $ route ->getGroups ();
@@ -799,82 +844,7 @@ private function runInternal(Request $request, Response $response): static
799844 return $ this ;
800845 }
801846
802- $ method = $ request ->getMethod ();
803- $ match = $ this ->match ($ request );
804- $ groups = $ match instanceof RouteMatch ? $ match ->route ->getGroups () : [];
805-
806- if (self ::REQUEST_METHOD_HEAD === $ method ) {
807- $ method = self ::REQUEST_METHOD_GET ;
808- $ response ->disablePayload ();
809- }
810-
811- if (self ::REQUEST_METHOD_OPTIONS === $ method ) {
812- try {
813- foreach ($ groups as $ group ) {
814- foreach (self ::$ options as $ option ) { // Group options hooks
815- /** @var Hook $option */
816- if (\in_array ($ group , $ option ->getGroups ())) {
817- \call_user_func_array ($ option ->getAction (), $ this ->getArguments ($ option , [], $ request ->getParams ()));
818- }
819- }
820- }
821-
822- foreach (self ::$ options as $ option ) { // Global options hooks
823- /** @var Hook $option */
824- if (\in_array ('* ' , $ option ->getGroups ())) {
825- \call_user_func_array ($ option ->getAction (), $ this ->getArguments ($ option , [], $ request ->getParams ()));
826- }
827- }
828- } catch (\Throwable $ e ) {
829- foreach (self ::$ errors as $ error ) { // Global error hooks
830- /** @var Hook $error */
831- if (\in_array ('* ' , $ error ->getGroups ())) {
832- $ this ->context ()->set ('error ' , fn () => $ e , []);
833- \call_user_func_array ($ error ->getAction (), $ this ->getArguments ($ error , [], $ request ->getParams ()));
834- }
835- }
836- }
837-
838- return $ this ;
839- }
840-
841- if ($ match instanceof RouteMatch) {
842- return $ this ->execute ($ match , $ request , $ response );
843- }
844-
845- if (self ::REQUEST_METHOD_OPTIONS === $ method ) {
846- try {
847- foreach ($ groups as $ group ) {
848- foreach (self ::$ options as $ option ) { // Group options hooks
849- if (\in_array ($ group , $ option ->getGroups ())) {
850- \call_user_func_array ($ option ->getAction (), $ this ->getArguments ($ option , [], $ request ->getParams ()));
851- }
852- }
853- }
854-
855- foreach (self ::$ options as $ option ) { // Global options hooks
856- if (\in_array ('* ' , $ option ->getGroups ())) {
857- \call_user_func_array ($ option ->getAction (), $ this ->getArguments ($ option , [], $ request ->getParams ()));
858- }
859- }
860- } catch (\Throwable $ e ) {
861- foreach (self ::$ errors as $ error ) { // Global error hooks
862- if (\in_array ('* ' , $ error ->getGroups ())) {
863- $ this ->context ()->set ('error ' , fn () => $ e , []);
864- \call_user_func_array ($ error ->getAction (), $ this ->getArguments ($ error , [], $ request ->getParams ()));
865- }
866- }
867- }
868- } else {
869- foreach (self ::$ errors as $ error ) { // Global error hooks
870- if (\in_array ('* ' , $ error ->getGroups ())) {
871- $ this ->context ()->set ('error ' , fn () => new Exception ('Not Found ' , 404 ), []);
872- \call_user_func_array ($ error ->getAction (), $ this ->getArguments ($ error , [], $ request ->getParams ()));
873- }
874- }
875- }
876-
877- return $ this ;
847+ return $ this ->execute ($ request , $ response );
878848 }
879849
880850
0 commit comments