Total Complexity | 161 |
Total Lines | 1260 |
Duplicated Lines | 0 % |
Changes | 4 | ||
Bugs | 1 | Features | 1 |
Complex classes like Router often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Router, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
37 | class Router |
||
38 | { |
||
39 | use SingletonTrait; |
||
40 | |||
41 | /** |
||
42 | * The regular expression used to compile and match URL's |
||
43 | * |
||
44 | * @type string |
||
45 | */ |
||
46 | const ROUTE_COMPILE_REGEX = '`(\\\?(?:/|\.|))(?:\[([^:\]]*)(?::([^:\]]*))?\])(\?|)`'; |
||
47 | |||
48 | /** |
||
49 | * The regular expression used to escape the non-named param section of a route URL |
||
50 | * |
||
51 | * @type string |
||
52 | */ |
||
53 | const ROUTE_ESCAPE_REGEX = '`(?<=^|\])[^\]\[\?]+?(?=\[|$)`'; |
||
54 | |||
55 | /** |
||
56 | * Dispatch route output handling |
||
57 | * |
||
58 | * Don't capture anything. Behave as normal. |
||
59 | * |
||
60 | * @type int |
||
61 | */ |
||
62 | const DISPATCH_NO_CAPTURE = 0; |
||
63 | |||
64 | /** |
||
65 | * Dispatch route output handling |
||
66 | * |
||
67 | * Capture all output and return it from dispatch |
||
68 | * |
||
69 | * @type int |
||
70 | */ |
||
71 | const DISPATCH_CAPTURE_AND_RETURN = 1; |
||
72 | |||
73 | /** |
||
74 | * Dispatch route output handling |
||
75 | * |
||
76 | * Capture all output and replace the response body with it |
||
77 | * |
||
78 | * @type int |
||
79 | */ |
||
80 | const DISPATCH_CAPTURE_AND_REPLACE = 2; |
||
81 | |||
82 | /** |
||
83 | * Dispatch route output handling |
||
84 | * |
||
85 | * Capture all output and prepend it to the response body |
||
86 | * |
||
87 | * @type int |
||
88 | */ |
||
89 | const DISPATCH_CAPTURE_AND_PREPEND = 3; |
||
90 | |||
91 | /** |
||
92 | * Dispatch route output handling |
||
93 | * |
||
94 | * Capture all output and append it to the response body |
||
95 | * |
||
96 | * @type int |
||
97 | */ |
||
98 | const DISPATCH_CAPTURE_AND_APPEND = 4; |
||
99 | |||
100 | /** |
||
101 | * The types to detect in a defined match "block" |
||
102 | * |
||
103 | * Examples of these blocks are as follows: |
||
104 | * |
||
105 | * - integer: '[i:id]' |
||
106 | * - alphanumeric: '[a:username]' |
||
107 | * - hexadecimal: '[h:color]' |
||
108 | * - slug: '[s:article]' |
||
109 | * |
||
110 | * @type array |
||
111 | */ |
||
112 | protected $match_types = [ |
||
113 | 'i' => '[0-9]++', |
||
114 | 'a' => '[0-9A-Za-z]++', |
||
115 | 'h' => '[0-9A-Fa-f]++', |
||
116 | 's' => '[0-9A-Za-z-_]++', |
||
117 | '*' => '.+?', |
||
118 | '**' => '.++', |
||
119 | '' => '[^/]+?', |
||
120 | ]; |
||
121 | |||
122 | /** |
||
123 | * Collection of the routes to match on dispatch |
||
124 | * |
||
125 | * @type RouteCollection |
||
126 | */ |
||
127 | protected $routes; |
||
128 | |||
129 | /** |
||
130 | * The Route factory object responsible for creating Route instances |
||
131 | * |
||
132 | * @type AbstractRouteFactory |
||
133 | */ |
||
134 | protected $route_factory; |
||
135 | |||
136 | /** |
||
137 | * A stack of error callback callables |
||
138 | * |
||
139 | * @type SplStack |
||
140 | */ |
||
141 | protected $error_callbacks; |
||
142 | |||
143 | /** |
||
144 | * A stack of HTTP error callback callables |
||
145 | * |
||
146 | * @type SplStack |
||
147 | */ |
||
148 | protected $http_error_callbacks; |
||
149 | |||
150 | /** |
||
151 | * A queue of callbacks to call after processing the dispatch loop |
||
152 | * and before the response is sent |
||
153 | * |
||
154 | * @type SplQueue |
||
155 | */ |
||
156 | protected $after_filter_callbacks; |
||
157 | |||
158 | /** |
||
159 | * The output buffer level used by the dispatch process |
||
160 | * |
||
161 | * @type int |
||
162 | */ |
||
163 | private $output_buffer_level; |
||
164 | |||
165 | /** |
||
166 | * The Request object passed to each matched route |
||
167 | * |
||
168 | * @type Request |
||
169 | */ |
||
170 | protected $request; |
||
171 | |||
172 | /** |
||
173 | * The Response object passed to each matched route |
||
174 | * |
||
175 | * @type AbstractResponse |
||
176 | */ |
||
177 | protected $response; |
||
178 | |||
179 | /** |
||
180 | * The service provider object passed to each matched route |
||
181 | * |
||
182 | * @type ServiceProvider |
||
183 | */ |
||
184 | protected $service; |
||
185 | |||
186 | /** |
||
187 | * A generic variable passed to each matched route |
||
188 | * |
||
189 | * @type mixed |
||
190 | */ |
||
191 | protected $app; |
||
192 | |||
193 | /** |
||
194 | * Constructor |
||
195 | * |
||
196 | * Create a new Klein instance with optionally injected dependencies |
||
197 | * This DI allows for easy testing, object mocking, or class extension |
||
198 | * |
||
199 | * @param ServiceProvider $service Service provider object responsible for utilitarian behaviors |
||
200 | * @param mixed $app An object passed to each route callback, defaults to an App instance |
||
201 | * @param RouteCollection $routes Collection object responsible for containing all route instances |
||
202 | * @param AbstractRouteFactory $route_factory A factory class responsible for creating Route instances |
||
203 | */ |
||
204 | public function __construct( |
||
205 | ServiceProvider $service = null, |
||
206 | $app = null, |
||
207 | RouteCollection $routes = null, |
||
208 | AbstractRouteFactory $route_factory = null |
||
209 | ) { |
||
210 | // Instantiate and fall back to defaults |
||
211 | $this->service = $service ?: new ServiceProvider(); |
||
212 | $this->app = $app ?: new App(); |
||
213 | $this->routes = $routes ?: new RouteCollection(); |
||
214 | $this->route_factory = $route_factory ?: new RouteFactory(); |
||
215 | |||
216 | $this->error_callbacks = new SplStack(); |
||
217 | $this->http_error_callbacks = new SplStack(); |
||
218 | $this->after_filter_callbacks = new SplQueue(); |
||
219 | } |
||
220 | |||
221 | /** |
||
222 | * Returns the routes object |
||
223 | * |
||
224 | * @return RouteCollection |
||
225 | */ |
||
226 | public function routes() |
||
227 | { |
||
228 | return $this->routes; |
||
229 | } |
||
230 | |||
231 | /** |
||
232 | * Returns the request object |
||
233 | * |
||
234 | * @return Request |
||
235 | */ |
||
236 | public function request() |
||
237 | { |
||
238 | return $this->request; |
||
239 | } |
||
240 | |||
241 | /** |
||
242 | * Returns the response object |
||
243 | * |
||
244 | * @return Response |
||
245 | */ |
||
246 | public function response() |
||
247 | { |
||
248 | return $this->response; |
||
249 | } |
||
250 | |||
251 | /** |
||
252 | * Returns the service object |
||
253 | * |
||
254 | * @return ServiceProvider |
||
255 | */ |
||
256 | public function service() |
||
257 | { |
||
258 | return $this->service; |
||
259 | } |
||
260 | |||
261 | /** |
||
262 | * Returns the app object |
||
263 | * |
||
264 | * @return mixed |
||
265 | */ |
||
266 | public function app() |
||
269 | } |
||
270 | |||
271 | /** |
||
272 | * Parse our extremely loose argument order of our "respond" method and its aliases |
||
273 | * |
||
274 | * This method takes its arguments in a loose format and order. |
||
275 | * The method signature is simply there for documentation purposes, but allows |
||
276 | * for the minimum of a callback to be passed in its current configuration. |
||
277 | * |
||
278 | * @see Routing::respond() |
||
279 | * @param mixed $args An argument array. Hint: This works well when passing "func_get_args()" |
||
280 | * @named string | array $method HTTP Method to match |
||
281 | * @named string $path Route URI path to match |
||
282 | * @named callable $callback Callable callback method to execute on route match |
||
283 | * @return array A named parameter array containing the keys: 'method', 'path', and 'callback' |
||
284 | */ |
||
285 | protected function parseLooseArgumentOrder(array $args) |
||
297 | ]; |
||
298 | } |
||
299 | |||
300 | /** |
||
301 | * Add a new route to be matched on dispatch |
||
302 | * |
||
303 | * Essentially, this method is a standard "Route" builder/factory, |
||
304 | * allowing a loose argument format and a standard way of creating |
||
305 | * Route instances |
||
306 | * |
||
307 | * This method takes its arguments in a very loose format |
||
308 | * The only "required" parameter is the callback (which is very strange considering the argument definition order) |
||
309 | * |
||
310 | * <code> |
||
311 | * $router = new Klein(); |
||
312 | * |
||
313 | * $router->respond( function() { |
||
314 | * echo 'this works'; |
||
315 | * }); |
||
316 | * $router->respond( '/endpoint', function() { |
||
317 | * echo 'this also works'; |
||
318 | * }); |
||
319 | * $router->respond( 'POST', '/endpoint', function() { |
||
320 | * echo 'this also works!!!!'; |
||
321 | * }); |
||
322 | * </code> |
||
323 | * |
||
324 | * @param string|array $method HTTP Method to match |
||
325 | * @param string $path Route URI path to match |
||
326 | * @param callable $callback Callable callback method to execute on route match |
||
327 | * @return Route |
||
328 | */ |
||
329 | public function respond($method, $path = '*', $callback = null) |
||
342 | } |
||
343 | |||
344 | /** |
||
345 | * Collect a set of routes under a common namespace |
||
346 | * |
||
347 | * The routes may be passed in as either a callable (which holds the route definitions), |
||
348 | * or as a string of a filename, of which to "include" under the Klein router scope |
||
349 | * |
||
350 | * <code> |
||
351 | * $router = new Klein(); |
||
352 | * |
||
353 | * $router->with('/users', function($router) { |
||
354 | * $router->respond( '/', function() { |
||
355 | * // do something interesting |
||
356 | * }); |
||
357 | * $router->respond( '/[i:id]', function() { |
||
358 | * // do something different |
||
359 | * }); |
||
360 | * }); |
||
361 | * |
||
362 | * $router->with('/cars', __DIR__ . '/routes/cars.php'); |
||
363 | * </code> |
||
364 | * |
||
365 | * @param string $namespace The namespace under which to collect the routes |
||
366 | * @param callable|string $routes The defined routes callable or filename to collect under the namespace |
||
367 | * @return void |
||
368 | */ |
||
369 | public function with($namespace, $routes) |
||
386 | } |
||
387 | |||
388 | /** |
||
389 | * Dispatch the request to the appropriate route(s) |
||
390 | * |
||
391 | * Dispatch with optionally injected dependencies |
||
392 | * This DI allows for easy testing, object mocking, or class extension |
||
393 | * |
||
394 | * @param Request $request The request object to give to each callback |
||
395 | * @param AbstractResponse $response The response object to give to each callback |
||
396 | * @param boolean $send_response Whether or not to "send" the response after the last route has been matched |
||
397 | * @param int $capture Specify a DISPATCH_* constant to change the output capturing behavior |
||
398 | * @return void|string |
||
399 | * @throws Throwable |
||
400 | */ |
||
401 | public function dispatch( |
||
698 | } |
||
699 | } |
||
700 | |||
701 | /** |
||
702 | * Execute middleware handle method |
||
703 | * |
||
704 | * @param Route $route |
||
705 | * @throws Exceptions\MiddlewareNotFoundException |
||
706 | */ |
||
707 | protected function doMiddleware(Route $route) |
||
708 | { |
||
709 | /** @var MiddlewareInterface $middleware */ |
||
710 | foreach($route->getMiddleware() as $middleware) { |
||
711 | if (is_array($middleware)) { |
||
712 | foreach ($middleware as $group) { |
||
713 | $group->handle($this->request()); |
||
714 | } |
||
715 | } else { |
||
716 | $middleware->handle($this->request()); |
||
717 | } |
||
718 | } |
||
719 | } |
||
720 | |||
721 | /** |
||
722 | * Compiles a route string to a regular expression |
||
723 | * |
||
724 | * @param string $route The route string to compile |
||
725 | * @return string |
||
726 | */ |
||
727 | protected function compileRoute($route) |
||
728 | { |
||
729 | // First escape all of the non-named param (non [block]s) for regex-chars |
||
730 | $route = preg_replace_callback( |
||
731 | static::ROUTE_ESCAPE_REGEX, |
||
732 | function ($match) { |
||
733 | return preg_quote($match[0]); |
||
734 | }, |
||
735 | $route |
||
736 | ); |
||
737 | |||
738 | // Get a local reference of the match types to pass into our closure |
||
739 | $match_types = $this->match_types; |
||
740 | |||
741 | // Now let's actually compile the path |
||
742 | $route = preg_replace_callback( |
||
743 | static::ROUTE_COMPILE_REGEX, |
||
744 | function ($match) use ($match_types) { |
||
745 | list(, $pre, $type, $param, $optional) = $match; |
||
746 | |||
747 | if (isset($match_types[$type])) { |
||
748 | $type = $match_types[$type]; |
||
749 | } |
||
750 | |||
751 | // Older versions of PCRE require the 'P' in (?P<named>) |
||
752 | $pattern = '(?:' |
||
753 | . ($pre !== '' ? $pre : null) |
||
754 | . '(' |
||
755 | . ($param !== '' ? "?P<$param>" : null) |
||
756 | . $type |
||
757 | . '))' |
||
758 | . ($optional !== '' ? '?' : null); |
||
759 | |||
760 | return $pattern; |
||
761 | }, |
||
762 | $route |
||
763 | ); |
||
764 | |||
765 | $regex = "`^$route$`"; |
||
766 | |||
767 | // Check if our regular expression is valid |
||
768 | $this->validateRegularExpression($regex); |
||
769 | |||
770 | return $regex; |
||
771 | } |
||
772 | |||
773 | /** |
||
774 | * Validate a regular expression |
||
775 | * |
||
776 | * This simply checks if the regular expression is able to be compiled |
||
777 | * and converts any warnings or notices in the compilation to an exception |
||
778 | * |
||
779 | * @param string $regex The regular expression to validate |
||
780 | * @throws RegularExpressionCompilationException If the expression can't be compiled |
||
781 | * @return boolean |
||
782 | */ |
||
783 | private function validateRegularExpression($regex) |
||
784 | { |
||
785 | $error_string = null; |
||
786 | |||
787 | // Set an error handler temporarily |
||
788 | set_error_handler( |
||
789 | function ($errno, $errstr) use (&$error_string) { |
||
790 | $error_string = $errstr; |
||
791 | }, |
||
792 | E_NOTICE | E_WARNING |
||
793 | ); |
||
794 | |||
795 | if (false === preg_match($regex, null) || !empty($error_string)) { |
||
796 | // Remove our temporary error handler |
||
797 | restore_error_handler(); |
||
798 | |||
799 | throw new RegularExpressionCompilationException( |
||
800 | $error_string, |
||
801 | preg_last_error() |
||
802 | ); |
||
803 | } |
||
804 | |||
805 | // Remove our temporary error handler |
||
806 | restore_error_handler(); |
||
807 | |||
808 | return true; |
||
809 | } |
||
810 | |||
811 | /** |
||
812 | * Get the path for a given route |
||
813 | * |
||
814 | * This looks up the route by its passed name and returns |
||
815 | * the path/url for that route, with its URL params as |
||
816 | * placeholders unless you pass a valid key-value pair array |
||
817 | * of the placeholder params and their values |
||
818 | * |
||
819 | * If a pathname is a complex/custom regular expression, this |
||
820 | * method will simply return the regular expression used to |
||
821 | * match the request pathname, unless an optional boolean is |
||
822 | * passed "flatten_regex" which will flatten the regular |
||
823 | * expression into a simple path string |
||
824 | * |
||
825 | * This method, and its style of reverse-compilation, was originally |
||
826 | * inspired by a similar effort by Gilles Bouthenot (@gbouthenot) |
||
827 | * |
||
828 | * @link https://github.com/gbouthenot |
||
829 | * @param string $route_name The name of the route |
||
830 | * @param array $params The array of placeholder fillers |
||
831 | * @param boolean $flatten_regex Optionally flatten custom regular expressions to "/" |
||
832 | * @throws OutOfBoundsException If the route requested doesn't exist |
||
833 | * @return string |
||
834 | */ |
||
835 | public function getPathFor($route_name, array $params = null, $flatten_regex = true) |
||
836 | { |
||
837 | // First, grab the route |
||
838 | $route = $this->routes->get($route_name); |
||
839 | |||
840 | // Make sure we are getting a valid route |
||
841 | if (null === $route) { |
||
842 | throw new OutOfBoundsException('No such route with name: '. $route_name); |
||
843 | } |
||
844 | |||
845 | $path = $route->getPath(); |
||
846 | |||
847 | // Use our compilation regex to reverse the path's compilation from its definition |
||
848 | $reversed_path = preg_replace_callback( |
||
849 | static::ROUTE_COMPILE_REGEX, |
||
850 | function ($match) use ($params) { |
||
851 | list($block, $pre, , $param, $optional) = $match; |
||
852 | |||
853 | if (isset($params[$param])) { |
||
854 | return $pre. $params[$param]; |
||
855 | } elseif ($optional) { |
||
856 | return ''; |
||
857 | } |
||
858 | |||
859 | return $block; |
||
860 | }, |
||
861 | $path |
||
862 | ); |
||
863 | |||
864 | // If the path and reversed_path are the same, the regex must have not matched/replaced |
||
865 | if ($path === $reversed_path && $flatten_regex && strpos($path, '@') === 0) { |
||
866 | // If the path is a custom regular expression and we're "flattening", just return a slash |
||
867 | $path = '/'; |
||
868 | } else { |
||
869 | $path = $reversed_path; |
||
870 | } |
||
871 | |||
872 | return $path; |
||
873 | } |
||
874 | |||
875 | /** |
||
876 | * Handle a route's callback |
||
877 | * |
||
878 | * This handles common exceptions and their output |
||
879 | * to keep the "dispatch()" method DRY |
||
880 | * |
||
881 | * @param Route $route |
||
882 | * @param RouteCollection $matched |
||
883 | * @param array $methods_matched |
||
884 | * @return void |
||
885 | */ |
||
886 | protected function handleRouteCallback(Route $route, RouteCollection $matched, array $methods_matched) |
||
887 | { |
||
888 | $callback = $route->getCallback(); |
||
889 | |||
890 | $params = [ |
||
891 | $this->request, |
||
892 | $this->response, |
||
893 | $this->service, |
||
894 | $this->app, |
||
895 | // Pass the Klein instance |
||
896 | $this, |
||
897 | $matched, |
||
898 | $methods_matched, |
||
899 | ]; |
||
900 | |||
901 | if (is_string($callback)) { |
||
902 | $returned = app($callback, $params); |
||
903 | } else { |
||
904 | // Handle the callback |
||
905 | $returned = call_user_func( |
||
906 | // Instead of relying on the slower "invoke" magic |
||
907 | $callback, |
||
908 | $this->request, |
||
909 | $this->response, |
||
910 | $this->service, |
||
911 | $this->app, |
||
912 | // Pass the Klein instance |
||
913 | $this, |
||
914 | $matched, |
||
915 | $methods_matched |
||
916 | ); |
||
917 | } |
||
918 | |||
919 | if ($returned instanceof AbstractResponse) { |
||
920 | $this->response = $returned; |
||
921 | } else { |
||
922 | // Otherwise, attempt to append the returned data |
||
923 | try { |
||
924 | $this->response->append($returned); |
||
925 | } catch (LockedResponseException $e) { |
||
926 | // Do nothing, since this is an automated behavior |
||
927 | } |
||
928 | } |
||
929 | } |
||
930 | |||
931 | /** |
||
932 | * Adds an error callback to the stack of error handlers |
||
933 | * |
||
934 | * @param callable $callback The callable function to execute in the error handling chain |
||
935 | * @return void |
||
936 | */ |
||
937 | public function onError($callback) |
||
938 | { |
||
939 | $this->error_callbacks->push($callback); |
||
940 | } |
||
941 | |||
942 | /** |
||
943 | * Routes an exception through the error callbacks |
||
944 | * |
||
945 | * @param Exception|Throwable $err The exception that occurred |
||
946 | * @return void |
||
947 | * @throws Throwable |
||
948 | * @throws UnhandledException If the error/exception isn't handled by an error callback |
||
949 | */ |
||
950 | protected function error(Throwable $err) |
||
951 | { |
||
952 | $type = get_class($err); |
||
953 | $msg = $err->getMessage(); |
||
954 | |||
955 | try { |
||
956 | if (!$this->error_callbacks->isEmpty()) { |
||
957 | foreach ($this->error_callbacks as $callback) { |
||
958 | if (is_callable($callback)) { |
||
959 | if (is_string($callback)) { |
||
960 | $callback($this, $msg, $type, $err); |
||
961 | |||
962 | return; |
||
963 | } else { |
||
964 | call_user_func($callback, $this, $msg, $type, $err); |
||
965 | |||
966 | return; |
||
967 | } |
||
968 | } else { |
||
969 | if (null !== $this->service && null !== $this->response) { |
||
970 | $this->service->flash($err); |
||
971 | $this->response->redirect($callback); |
||
972 | } |
||
973 | } |
||
974 | } |
||
975 | } else { |
||
976 | $this->response->code(500); |
||
977 | |||
978 | while (ob_get_level() >= $this->output_buffer_level) { |
||
979 | ob_end_clean(); |
||
980 | } |
||
981 | |||
982 | throw $err; |
||
983 | } |
||
984 | } catch (Throwable $e) { // PHP 7 compatibility |
||
985 | // Make sure to clean the output buffer before bailing |
||
986 | while (ob_get_level() >= $this->output_buffer_level) { |
||
987 | ob_end_clean(); |
||
988 | } |
||
989 | |||
990 | throw $e; |
||
991 | } |
||
992 | |||
993 | // Lock our response, since we probably don't want |
||
994 | // anything else messing with our error code/body |
||
995 | $this->response->lock(); |
||
996 | } |
||
997 | |||
998 | /** |
||
999 | * Adds an HTTP error callback to the stack of HTTP error handlers |
||
1000 | * |
||
1001 | * @param callable $callback The callable function to execute in the error handling chain |
||
1002 | * @return void |
||
1003 | */ |
||
1004 | public function onHttpError($callback) |
||
1005 | { |
||
1006 | $this->http_error_callbacks->push($callback); |
||
1007 | } |
||
1008 | |||
1009 | /** |
||
1010 | * Handles an HTTP error exception through our HTTP error callbacks |
||
1011 | * |
||
1012 | * @param HttpExceptionInterface $http_exception The exception that occurred |
||
1013 | * @param RouteCollection $matched The collection of routes that were matched in dispatch |
||
1014 | * @param array $methods_matched The HTTP methods that were matched in dispatch |
||
1015 | * @return void |
||
1016 | */ |
||
1017 | protected function httpError(HttpExceptionInterface $http_exception, RouteCollection $matched, $methods_matched) |
||
1018 | { |
||
1019 | if (!$this->response->isLocked()) { |
||
1020 | $this->response->code($http_exception->getCode()); |
||
1021 | } |
||
1022 | |||
1023 | if (!$this->http_error_callbacks->isEmpty()) { |
||
1024 | foreach ($this->http_error_callbacks as $callback) { |
||
1025 | if ($callback instanceof Route) { |
||
1026 | $this->handleRouteCallback($callback, $matched, $methods_matched); |
||
1027 | } elseif (is_callable($callback)) { |
||
1028 | if (is_string($callback)) { |
||
1029 | $callback( |
||
1030 | $http_exception->getCode(), |
||
1031 | $this, |
||
1032 | $matched, |
||
1033 | $methods_matched, |
||
1034 | $http_exception |
||
1035 | ); |
||
1036 | } else { |
||
1037 | call_user_func( |
||
1038 | $callback, |
||
1039 | $http_exception->getCode(), |
||
1040 | $this, |
||
1041 | $matched, |
||
1042 | $methods_matched, |
||
1043 | $http_exception |
||
1044 | ); |
||
1045 | } |
||
1046 | } |
||
1047 | } |
||
1048 | } |
||
1049 | |||
1050 | // Lock our response, since we probably don't want |
||
1051 | // anything else messing with our error code/body |
||
1052 | $this->response->lock(); |
||
1053 | } |
||
1054 | |||
1055 | /** |
||
1056 | * Adds a callback to the stack of handlers to run after the dispatch |
||
1057 | * loop has handled all of the route callbacks and before the response |
||
1058 | * is sent |
||
1059 | * |
||
1060 | * @param callable $callback The callable function to execute in the after route chain |
||
1061 | * @return void |
||
1062 | */ |
||
1063 | public function afterDispatch($callback) |
||
1064 | { |
||
1065 | $this->after_filter_callbacks->enqueue($callback); |
||
1066 | } |
||
1067 | |||
1068 | /** |
||
1069 | * Runs through and executes the after dispatch callbacks |
||
1070 | * |
||
1071 | * @return void |
||
1072 | */ |
||
1073 | protected function callAfterDispatchCallbacks() |
||
1074 | { |
||
1075 | try { |
||
1076 | foreach ($this->after_filter_callbacks as $callback) { |
||
1077 | if (is_callable($callback)) { |
||
1078 | if (is_string($callback)) { |
||
1079 | $callback($this); |
||
1080 | |||
1081 | } else { |
||
1082 | call_user_func($callback, $this); |
||
1083 | |||
1084 | } |
||
1085 | } |
||
1086 | } |
||
1087 | } catch (Throwable $e) { // PHP 7 compatibility |
||
1088 | $this->error($e); |
||
1089 | } catch (Exception $e) { // TODO: Remove this catch block once PHP 5.x support is no longer necessary. |
||
1090 | $this->error($e); |
||
1091 | } |
||
1092 | } |
||
1093 | |||
1094 | /** |
||
1095 | * Quick alias to skip the current callback/route method from executing |
||
1096 | * |
||
1097 | * @throws DispatchHaltedException To halt/skip the current dispatch loop |
||
1098 | * @return void |
||
1099 | */ |
||
1100 | public function skipThis() |
||
1101 | { |
||
1102 | throw new DispatchHaltedException(null, DispatchHaltedException::SKIP_THIS); |
||
1103 | } |
||
1104 | |||
1105 | /** |
||
1106 | * Quick alias to skip the next callback/route method from executing |
||
1107 | * |
||
1108 | * @param int $num The number of next matches to skip |
||
1109 | * @throws DispatchHaltedException To halt/skip the current dispatch loop |
||
1110 | * @return void |
||
1111 | */ |
||
1112 | public function skipNext($num = 1) |
||
1113 | { |
||
1114 | $skip = new DispatchHaltedException(null, DispatchHaltedException::SKIP_NEXT); |
||
1115 | $skip->setNumberOfSkips($num); |
||
1116 | |||
1117 | throw $skip; |
||
1118 | } |
||
1119 | |||
1120 | /** |
||
1121 | * Quick alias to stop the remaining callbacks/route methods from executing |
||
1122 | * |
||
1123 | * @throws DispatchHaltedException To halt/skip the current dispatch loop |
||
1124 | * @return void |
||
1125 | */ |
||
1126 | public function skipRemaining() |
||
1127 | { |
||
1128 | throw new DispatchHaltedException(null, DispatchHaltedException::SKIP_REMAINING); |
||
1129 | } |
||
1130 | |||
1131 | /** |
||
1132 | * Alias to set a response code, lock the response, and halt the route matching/dispatching |
||
1133 | * |
||
1134 | * @param int $code Optional HTTP status code to send |
||
1135 | * @throws DispatchHaltedException To halt/skip the current dispatch loop |
||
1136 | * @return void |
||
1137 | */ |
||
1138 | public function abort($code = null) |
||
1139 | { |
||
1140 | if (null !== $code) { |
||
1141 | throw HttpException::createFromCode($code); |
||
1142 | } |
||
1143 | |||
1144 | throw new DispatchHaltedException(); |
||
1145 | } |
||
1146 | |||
1147 | /** |
||
1148 | * OPTIONS alias for "respond()" |
||
1149 | * |
||
1150 | * @see Routing::respond() |
||
1151 | * @param string $path |
||
1152 | * @param callable $callback |
||
1153 | * @return Route |
||
1154 | */ |
||
1155 | public function options($path = '*', $callback = null) |
||
1156 | { |
||
1157 | // Options the arguments in a very loose format |
||
1158 | extract( |
||
1159 | $this->parseLooseArgumentOrder(func_get_args()), |
||
1160 | EXTR_OVERWRITE |
||
1161 | ); |
||
1162 | |||
1163 | return $this->respond('OPTIONS', $path, $callback); |
||
1164 | } |
||
1165 | |||
1166 | /** |
||
1167 | * HEAD alias for "respond()" |
||
1168 | * |
||
1169 | * @see Routing::respond() |
||
1170 | * @param string $path |
||
1171 | * @param callable $callback |
||
1172 | * @return Route |
||
1173 | */ |
||
1174 | public function head($path = '*', $callback = null) |
||
1175 | { |
||
1176 | // Get the arguments in a very loose format |
||
1177 | extract( |
||
1178 | $this->parseLooseArgumentOrder(func_get_args()), |
||
1179 | EXTR_OVERWRITE |
||
1180 | ); |
||
1181 | |||
1182 | return $this->respond('HEAD', $path, $callback); |
||
1183 | } |
||
1184 | |||
1185 | /** |
||
1186 | * GET alias for "respond()" |
||
1187 | * |
||
1188 | * @see Routing::respond() |
||
1189 | * @param string $path |
||
1190 | * @param callable $callback |
||
1191 | * @return Route |
||
1192 | */ |
||
1193 | public static function get($path = '*', $callback = null) |
||
1194 | { |
||
1195 | // Get the arguments in a very loose format |
||
1196 | extract( |
||
1197 | Router::getInstance()->parseLooseArgumentOrder(func_get_args()), |
||
1198 | EXTR_OVERWRITE |
||
1199 | ); |
||
1200 | |||
1201 | return Router::getInstance()->respond('GET', $path, $callback); |
||
1202 | } |
||
1203 | |||
1204 | /** |
||
1205 | * POST alias for "respond()" |
||
1206 | * |
||
1207 | * @see Routing::respond() |
||
1208 | * @param string $path |
||
1209 | * @param callable $callback |
||
1210 | * @return Route |
||
1211 | */ |
||
1212 | public static function post($path = '*', $callback = null) |
||
1213 | { |
||
1214 | // Get the arguments in a very loose format |
||
1215 | extract( |
||
1216 | Router::getInstance()->parseLooseArgumentOrder(func_get_args()), |
||
1217 | EXTR_OVERWRITE |
||
1218 | ); |
||
1219 | |||
1220 | return Router::getInstance()->respond('POST', $path, $callback); |
||
1221 | } |
||
1222 | |||
1223 | /** |
||
1224 | * PUT alias for "respond()" |
||
1225 | * |
||
1226 | * @see Routing::respond() |
||
1227 | * @param string $path |
||
1228 | * @param callable $callback |
||
1229 | * @return Route |
||
1230 | */ |
||
1231 | public static function put($path = '*', $callback = null) |
||
1240 | } |
||
1241 | |||
1242 | /** |
||
1243 | * DELETE alias for "respond()" |
||
1244 | * |
||
1245 | * @see Routing::respond() |
||
1246 | * @param string $path |
||
1247 | * @param callable $callback |
||
1248 | * @return Route |
||
1249 | */ |
||
1250 | public static function delete($path = '*', $callback = null) |
||
1259 | } |
||
1260 | |||
1261 | /** |
||
1262 | * PATCH alias for "respond()" |
||
1263 | * |
||
1264 | * PATCH was added to HTTP/1.1 in RFC5789 |
||
1265 | * |
||
1266 | * @link http://tools.ietf.org/html/rfc5789 |
||
1267 | * @see Routing::respond() |
||
1268 | * @param string $path |
||
1269 | * @param callable $callback |
||
1270 | * @return Route |
||
1271 | */ |
||
1272 | public static function patch($path = '*', $callback = null) |
||
1273 | { |
||
1274 | // Get the arguments in a very loose format |
||
1275 | extract( |
||
1276 | Router::getInstance()->parseLooseArgumentOrder(func_get_args()), |
||
1277 | EXTR_OVERWRITE |
||
1278 | ); |
||
1279 | |||
1280 | return Router::getInstance()->respond('PATCH', $path, $callback); |
||
1281 | } |
||
1282 | |||
1283 | /** |
||
1284 | * Holding all the Auth routes |
||
1285 | */ |
||
1286 | public static function auth(): void |
||
1297 | } |
||
1298 | } |
||
1299 |
The
break
statement is not necessary if it is preceded for example by areturn
statement:If you would like to keep this construct to be consistent with other
case
statements, you can safely mark this issue as a false-positive.