PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 1.30
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v1.30
2.1.0 2.0.15 2.0.12 2.0.10 2.0.4 2.0.1 2.0.0 1.95.3 1.95.2 1.95 1.91.6 trunk 1.11 1.12 1.13 1.20 1.21 1.22 1.23 1.30 1.31 1.32 1.35 1.40 1.41 All 42 releases
fluent-boards / vendor / wpfluent / framework / src / WPFluent / Http / Route.php

Route.php in FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration 1.30, at vendor/wpfluent/framework/src/WPFluent/Http/Route.php

1,023 lines 26.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBoards\Framework\Http;
4
5 use Closure;
6 use Exception;
7 use WP_REST_Request;
8 use WP_REST_Response;
9 use BadMethodCallException;
10 use InvalidArgumentException;
11 use FluentBoards\Framework\Support\Arr;
12 use FluentBoards\Framework\Support\Pipeline;
13 use FluentBoards\Framework\Validator\ValidationException;
14 use FluentBoards\Framework\Database\Orm\ModelNotFoundException;
15 use FluentBoards\Framework\Response\Response as WPFluentResponse;
16
17 class Route
18 {
19 use SubstituteRouteParametersTrait;
20
21 /**
22 * Application Instance
23 * @var \FluentBoards\Framework\Foundation\Application
24 */
25 protected $app = null;
26
27 /**
28 * Rest namespace from config
29 * @var string
30 */
31 protected $restNamespace = null;
32
33 /**
34 * Full URI
35 * @var string
36 */
37 protected $uri = null;
38
39 /**
40 * Compiled rest endpoint
41 * @var string
42 */
43 protected $compiled = null;
44
45 /**
46 * Route meta data
47 * @var array
48 */
49 protected $meta = [];
50
51 /**
52 * Rest Handler/Callback before parsing
53 * @var string
54 */
55 protected $handler = null;
56
57 /**
58 * Rest Handler/Callback after parsing
59 * @var callable|string
60 */
61 protected $action = null;
62
63 /**
64 * Rest route action info after parsing
65 * @var array
66 */
67 protected $actionInfo = [];
68
69 /**
70 * Policy Handler/Callback after parsing
71 * @var string
72 */
73 protected $permissionHandler = [];
74
75 /**
76 * HTTP Methods
77 * @var string
78 */
79 protected $method = null;
80
81 /**
82 * Rest options
83 * @var array
84 */
85 protected $options = [];
86
87 /**
88 * Route where constraints
89 * @var array
90 */
91 protected $wheres = [];
92
93 /**
94 * Rest namespace
95 * @var string
96 */
97 protected $namespace = null;
98
99 /**
100 * Policy Handler/Callback after parsing
101 * @var callable|string
102 */
103 protected $policyHandler = null;
104
105 /**
106 * Route Middleware
107 * @var array
108 */
109 protected $middleware = [
110 'before' => [],
111 'after' => []
112 ];
113
114 /**
115 * Skips middlewar if true
116 *
117 * @var boolean
118 */
119 protected $skipMiddleware = false;
120
121 /**
122 * Predefined Regex foe where constraints
123 * @var array
124 */
125 protected $predefinedNamedRegx = [
126 'int' => '[0-9]+',
127 'alpha' => '[a-zA-Z]+',
128 'alpha_num' => '[a-zA-Z0-9]+',
129 'alpha_num_dash' => '[a-zA-Z0-9-_]+'
130 ];
131
132 /**
133 * Route parameters
134 * @var null|array
135 */
136 protected $parameters = null;
137
138 /**
139 * Route substituted parameters
140 *
141 * @var null|array
142 */
143 protected $substitutedParameters = [];
144
145 /**
146 * Construct the route instance
147 *
148 * @param \FluentBoards\Framework\Foundation\Application $app
149 * @param string $restNamespace
150 * @param string $uri
151 * @param string $handler
152 * @param string $method
153 */
154 public function __construct($app, $restNamespace, $uri, $handler, $method)
155 {
156 $this->app = $app;
157 $this->restNamespace = $restNamespace;
158 $this->uri = $uri;
159 $this->handler = $handler;
160 $this->method = $method;
161
162 $this->preparefrontendHandlers($handler);
163 }
164
165 /**
166 * Map the route to be used in front-end.
167 *
168 * @param mixed $handler
169 * @return null
170 */
171 protected function preparefrontendHandlers($handler)
172 {
173 $endpointsUrl = $this->app->config->get('app.slug') . '/__endpoints';
174
175 if (!str_contains($this->app->request->url(), $endpointsUrl)) {
176 return;
177 }
178
179 if ($handler instanceof Closure) {
180 return;
181 }
182
183 $action = trim($this->app->parseRestHandler($handler), '\\');
184
185 [$controller, $cb] = explode('@', $action);
186
187 $controller = str_replace('\\', '.', $controller);
188
189 $endpoints = $this->app->endpoints;
190
191 $endpoints[$controller]["_{$cb}"] = [
192 'uri' => $this->uri,
193 'methods' => explode(',', $this->method)
194 ];
195
196 $this->app->endpoints = $endpoints;
197 }
198
199 /**
200 * Alternative constructor
201 *
202 * @param \FluentBoards\Framework\Foundation\Application $app
203 * @param string $restNamespace
204 * @param string $uri
205 * @param string $handler
206 * @param string $method
207 * @return self
208 */
209 public static function create($app, $namespace, $uri, $handler, $method)
210 {
211 return new static($app, $namespace, $uri, $handler, $method);
212 }
213
214 /**
215 * Set route meta
216 *
217 * @param string $key
218 * @param mixed $value
219 * @return self
220 */
221 public function meta($key, $value = null)
222 {
223 $meta = is_array($key) ? $key : [$key => $value];
224
225 $this->meta = array_merge($this->meta, $meta);
226
227 return $this;
228 }
229
230 /**
231 * Get route meta
232 *
233 * @param string $key
234 * @return mixed
235 */
236 public function getMeta($key = '')
237 {
238 if (isset($this->meta[$key])) {
239 return $this->meta[$key];
240 }
241
242 return $this->meta;
243 }
244
245 /**
246 * Get route options
247 *
248 * @return mixed
249 */
250 public function getOptions()
251 {
252 return $this->getOption();
253 }
254
255 /**
256 * Get route options
257 *
258 * @param string $key
259 * @return mixed
260 */
261 public function getOption($key = null)
262 {
263 return $key ? $this->options[$key] : $this->options;
264 }
265
266 /**
267 * Get route action information
268 * @param string $key
269 * @return mixed
270 */
271 public function getAction($key = '')
272 {
273 if ($key && array_key_exists($key, $this->actionInfo)) {
274 return $this->actionInfo[$key];
275 }
276
277 return $this->actionInfo;
278 }
279
280 /**
281 * Set a where constrain into the route
282 *
283 * @param string $identifier
284 * @param string $value
285 * @return self
286 */
287 public function where($identifier, $value = null)
288 {
289 if (!is_null($value)) {
290 $this->wheres[$identifier] = $this->getValue($value);
291 } else {
292 foreach ($identifier as $key => $value) {
293 $this->wheres[$key] = $this->getValue($value);
294 }
295 }
296
297 return $this;
298 }
299
300 /**
301 * Add an integer type route constraint
302 *
303 * @param string $identifiers
304 * @return self
305 */
306 public function int($identifiers)
307 {
308 $identifiers = is_array($identifiers) ? $identifiers : func_get_args();
309
310 foreach ($identifiers as $identifier) {
311 $this->wheres[$identifier] = '[0-9]+';
312 }
313
314 return $this;
315 }
316
317 /**
318 * Add an alpha type route constraint
319 *
320 * @param string $identifiers
321 * @return self
322 */
323 public function alpha($identifiers)
324 {
325 $identifiers = is_array($identifiers) ? $identifiers : func_get_args();
326
327 foreach ($identifiers as $identifier) {
328 $this->wheres[$identifier] = '[a-zA-Z]+';
329 }
330
331 return $this;
332 }
333
334 /**
335 * Add an alphanum type route constraint
336 *
337 * @param string $identifiers
338 * @return self
339 */
340 public function alphaNum($identifiers)
341 {
342 $identifiers = is_array($identifiers) ? $identifiers : func_get_args();
343
344 foreach ($identifiers as $identifier) {
345 $this->wheres[$identifier] = '[a-zA-Z0-9]+';
346 }
347
348 return $this;
349 }
350
351 /**
352 * Add an alphanumdash type route constraint
353 *
354 * @param string $identifiers
355 * @return self
356 */
357 public function alphaNumDash($identifiers)
358 {
359 $identifiers = is_array($identifiers) ? $identifiers : func_get_args();
360
361 foreach ($identifiers as $identifier) {
362 $this->wheres[$identifier] = '[a-zA-Z0-9-_]+';
363 }
364
365 return $this;
366 }
367
368 /**
369 * Set the route before middleware
370 *
371 * @param array|string $middleware
372 * @return self
373 */
374 public function before(...$middleware)
375 {
376 return $this->middleware('before', ...$middleware);
377 }
378
379 /**
380 * Set the route after middleware
381 *
382 * @param array|string $middleware
383 * @return self
384 */
385 public function after(...$middleware)
386 {
387 return $this->middleware('after', ...$middleware);
388 }
389
390 /**
391 * Set the route middleware
392 * @param array $middleware
393 * @return self
394 */
395 public function middleware($type = 'before', ...$middleware)
396 {
397 if (is_array($middleware[0])) {
398 $middleware = reset($middleware);
399 }
400
401 $this->middleware[$type] = array_merge(
402 $this->middleware[$type], $middleware
403 );
404
405 return $this;
406 }
407
408 /**
409 * Set the route policy
410 *
411 * @param mixed $handler
412 * @param string|null $method
413 * @return self
414 */
415 public function withPolicy($handler, $method = null)
416 {
417 if (is_array($handler = $method ? func_get_args() : $handler)) {
418 $handler = implode('@', $handler);
419 }
420
421 $this->policyHandler = $handler;
422
423 if (is_string($handler) && !$this->app->hasNamespace($handler)) {
424 $this->setPolicyHandlerWithNamespace(
425 debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 4)
426 );
427 }
428
429 return $this;
430 }
431
432 /**
433 * Resolve and set policy with namespace for add-ons
434 *
435 * @param null
436 */
437 protected function setPolicyHandlerWithNamespace($backTrace)
438 {
439 $last = end($backTrace);
440
441 if (!isset($last['class'])) return;
442
443 $class = $last['class'];
444
445 $namespace = substr(__NAMESPACE__, 0, strpos(__NAMESPACE__, '\\'));
446
447 $calledClassNamespace = substr($class, 0, strpos($class, '\\'));
448
449 if ($namespace != $calledClassNamespace) {
450 $ns = $calledClassNamespace . '\\App\\Http\\Policies\\';
451 $this->policyHandler = $ns . $this->policyHandler;
452 }
453 }
454
455 /**
456 * Set the namespace for controller/action
457 * @param string $ns
458 * @return null
459 */
460 public function withNamespace($ns)
461 {
462 $this->namespace = implode('\\', $ns);
463 }
464
465 /**
466 * Register the rest endpoint
467 *
468 * @return null
469 */
470 public function register()
471 {
472 $this->setOptions();
473
474 $uri = '/' . trim($this->compileRoute($this->uri), '/');
475
476 return register_rest_route(
477 $this->restNamespace, $uri, $this->getOptions()
478 );
479 }
480
481 /**
482 * Set route options
483 *
484 * @return null
485 */
486 protected function setOptions()
487 {
488 $this->options = [
489 'args' => [],
490 'methods' => $this->method,
491 'callback' => [$this, 'callback'],
492 'permission_callback' => [$this, 'permissionCallback']
493 ];
494 }
495
496 /**
497 * Get item from predefined regex
498 * @param string $value
499 * @return string
500 */
501 protected function getValue($value)
502 {
503 if (array_key_exists($value, $this->predefinedNamedRegx)) {
504 return $this->predefinedNamedRegx[$value];
505 }
506
507 return $value;
508 }
509
510 /**
511 * Compikle the rest route to regex
512 *
513 * @param string $uri
514 * @return string compiled rest endpoint
515 */
516 protected function compileRoute($uri)
517 {
518 $params = [];
519
520 $compiledUri = preg_replace_callback('#/{(.*?)}#', function($match) use (&$params, $uri) {
521 // Default regx
522 $regx = '[^\s(?!/)]+';
523
524 $param = trim($match[1]);
525
526 if ($isOptional = strpos($param, '?')) {
527 $param = trim($param, '?');
528 }
529
530 if (in_array($param, $params)) {
531 throw new InvalidArgumentException(
532 "Duplicate parameter name '{$param}' found in {$uri}.", 500
533 );
534 }
535
536 $params[] = $param;
537
538 if (isset($this->wheres[$param])) {
539 $regx = $this->wheres[$param];
540 }
541
542 $pattern = "/(?P<" . $param . ">" . $regx . ")";
543
544 if ($isOptional) {
545 $pattern = "(?:" . $pattern . ")?";
546 }
547
548 $this->options['args'][$param]['required'] = !$isOptional;
549
550 return $pattern;
551
552 }, $uri);
553
554 return $this->compiled = $compiledUri;
555 }
556
557 /**
558 * Route handler
559 *
560 * @return mixed
561 */
562 public function callback()
563 {
564 try {
565
566 $response = $this->app->call(
567 $this->action, $this->getControllerParameters()
568 );
569
570 if ($response instanceof WPFluentResponse) {
571 $response = $response->toArray();
572 }
573
574 if (!($response instanceof WP_REST_Response)) {
575 if (is_wp_error($response)) {
576 $response = $this->app->response->wpErrorToResponse($response);
577 } else {
578 $response = $this->app->response->sendSuccess($response);
579 }
580 }
581
582 if (!$this->skipMiddleware) {
583 $response = $this->app->make(Pipeline::class)
584 ->send($response)
585 ->through($this->collectMiddleWare('after'))
586 ->then(function($response) {
587 if (!$response instanceof WP_REST_Response) {
588 $response = new WP_REST_Response($response);
589 }
590 return $response;
591 });
592
593 if (!$response) {
594 $response = $this->app->request->abort();
595 }
596 }
597
598 return $response;
599
600 } catch (ValidationException $e) {
601 return $this->app->response->sendError(
602 $e->errors(), $e->getCode()
603 );
604 } catch (ModelNotFoundException $e) {
605 return $this->app->response->sendError([
606 'message' => $e->getMessage()
607 ], 404);
608 } catch (Exception $e) {
609 return $this->app->response->sendError([
610 'message' => $e->getMessage()
611 ], $e->getCode() ?: 500);
612 }
613 }
614
615 /**
616 * Permission callback for route
617 * @param \WP_REST_Request $wpRestRequest
618 * @return mixed
619 */
620 public function permissionCallback($wpRestRequest)
621 {
622 try {
623
624 $this->app->instance('route', $this);
625
626 if (!$this->app->bound('wprestrequest')) {
627 $this->app->instance('wprestrequest', $wpRestRequest);
628 $this->app->request->mergeInputsFromRestRequest($wpRestRequest);
629
630 if (method_exists($this, 'prepareCallbacks')) {
631 $this->prepareCallbacks($this->app->request);
632 }
633 }
634
635 $response = $this->app->make(Pipeline::class)
636 ->send($this->app->request)
637 ->through($this->collectMiddleWare('before'))
638 ->then(function($request) {
639 return $this->dispatchPermissionHandler();
640 });
641
642 if (is_wp_error($response)) {
643 throw new Exception(
644 $response->get_error_message(),
645 is_int($code = $response->get_error_code()) ? $code : 403
646 );
647 }
648
649 if ($response instanceof WP_REST_Response) {
650 $data = $response->get_data();
651
652 throw new Exception(
653 $data['message'] ?? $response->get_status(), $response->get_status()
654 );
655 }
656
657 return $response;
658
659 } catch (Exception $e) {
660 $this->skipMiddleware = true;
661 $this->action = function() use ($e) {
662 return $this->app->response->sendError(
663 ['message' => $e->getMessage()], $e->getCode()
664 );
665 };
666 }
667 }
668
669 /**
670 * Dispatches the permission handler
671 *
672 * @return bool|null
673 */
674 protected function dispatchPermissionHandler()
675 {
676 if ($this->permissionHandler) {
677 return $this->app->call(
678 $this->permissionHandler,
679 $this->getControllerParameters()
680 );
681 }
682 }
683
684 /**
685 * Gether route params after substituted the params
686 *
687 * @return array
688 */
689 protected function getControllerParameters()
690 {
691 $routeParameters = [];
692
693 if (!$this->substitutedParameters) {
694 if ($routeParameters = $this->getParameter()) {
695 $routeParameters = $this->SubstituteParameters($routeParameters);
696 }
697 } else {
698 $routeParameters = $this->substitutedParameters;
699 }
700
701 return $routeParameters;
702 }
703
704 /**
705 * Added the ability to add middleware so we can intercept
706 * the request without modifying the source code again
707 * and again. The middleware class will implement
708 * the handle method as given below:
709 *
710 * public function handle($request, $next)
711 *
712 * And must return $next($request) to handle the request.
713 * Otherwise return nothing to abort the request.
714 * Optionally, you may call the abort method:
715 * return $request->abort(code, message);
716 *
717 * @param string $type
718 * @return array
719 */
720 protected function collectMiddleWare($type = 'before')
721 {
722 $middleware = $this->app['config']->get('middleware', []);
723
724 $callableMiddleware = Arr::get($middleware, "global.{$type}", []);
725
726 $routeArray = [];
727
728 if (isset($middleware['route'])) {
729 $routeArray = $middleware['route'];
730 if (isset($routeArray[$type])) {
731 $routeArray = $routeArray[$type];
732 }
733 }
734
735 foreach ($this->middleware[$type] as $routeMiddleware) {
736
737 if (is_object($routeMiddleware)) {
738 $handler = $routeMiddleware;
739 } else {
740 $pieces = explode(':', $routeMiddleware);
741 $handler = Arr::get($routeArray, $key = reset($pieces));
742
743 if (isset($pieces[1])) {
744 $handler = $this->resolveMiddleware($handler, $pieces);
745 }
746 }
747
748 if (isset($handler)) {
749 $this->addMiddlewareInTheStack($callableMiddleware, $handler);
750 } else {
751 if (isset($key)) {
752 $mpath = 'config.middleware.route.' . $type;
753 $msg = "No middleware is assigned for the key: {$key} in {$mpath} array.";
754 } else {
755 $msg = "Could't resolve middleware.";
756 }
757
758 throw new InvalidArgumentException($msg);
759 }
760 }
761
762 return $callableMiddleware;
763 }
764
765 /**
766 * Resolve the middleware
767 *
768 * @param mixed $handler
769 * @param aray $pieces
770 * @return object
771 */
772 protected function resolveMiddleware($handler, $pieces)
773 {
774 if (is_object($handler)) {
775 $handler = $this->wrapMiddleware($handler, $pieces);
776 } elseif (is_string($handler)) {
777 $handler = $handler . ':' . str_replace(' ', '', end($pieces));
778 }
779
780 return $handler;
781 }
782
783 /**
784 * Create a class to wrap the middleware
785 *
786 * @param mixed $handler
787 * @param aray $pieces
788 * @return object
789 */
790 protected function wrapMiddleware($handler, $pieces)
791 {
792 $params = str_replace(' ', '', end($pieces));
793
794 $params = explode(',', $params);
795
796 return new class ($handler, $params) {
797 protected $handler, $params = null;
798 public function __construct($handler, $params) {
799 $this->handler = $handler;
800 $this->params = $params;
801 }
802 public function handle($target, $next) {
803 if (is_callable($this->handler)) {
804 return ($this->handler)($target, $next, ...$this->params);
805 } else {
806 return $this->handler->handle(
807 $target, $next, ...$this->params
808 );
809 }
810 }
811 };
812 }
813
814 /**
815 * Add the middleware in the stack
816 *
817 * @param array &$stack All callable middleware for the route
818 * @param null
819 */
820 protected function addMiddlewareInTheStack(&$stack, $middleware)
821 {
822 if (!in_array($middleware, $stack)) {
823 $stack[] = $middleware;
824 }
825 }
826
827 /**
828 * Resolve the policy handler
829 *
830 * @param string $policyHandler
831 * @return mixed
832 */
833 protected function getPolicyHandler($policyHandler)
834 {
835 if (!$policyHandler) {
836 return [$this, 'defaultPolicyHandler'];
837 }
838
839 if (is_callable($policyHandler)) {
840 return $policyHandler;
841 }
842
843 if (is_string($policyHandler)) {
844
845 if (function_exists($policyHandler)) {
846 return $policyHandler;
847 }
848
849 $policyHandlerFunction = substr($policyHandler, strrpos($policyHandler, '\\') + 1);
850
851 if (function_exists($policyHandlerFunction)) {
852 return $policyHandlerFunction;
853 }
854 }
855
856 if ($this->isPolicyHandlerParseable($policyHandler)) {
857 return $policyHandler;
858 }
859
860 if (is_string($policyHandler) && $this->handler instanceof Closure) {
861
862 if (class_exists($policyHandler)) {
863
864 $reflection = new \ReflectionClass($policyHandler);
865
866 if ($reflection->hasMethod('verifyRequest')) {
867
868 $policyHandler = $policyHandler . '@' . 'verifyRequest';
869
870 return $policyHandler;
871 }
872 } elseif (function_exists($policyHandler)) {
873 return $policyHandler;
874 }
875
876 throw new InvalidArgumentException(
877 'Explicit policy handler is required while using a closure as route callback.'
878 );
879 }
880
881 if ($policyHandler && !function_exists($policyHandler)) {
882 if (is_string($this->handler) && strpos($this->handler, '@') !== false) {
883 list($_, $method) = explode('@', $this->handler);
884 $policyHandler = $policyHandler . '@' . $method;
885 } else if (is_array($this->handler)) {
886 $policyHandler = $policyHandler . '@' . $this->handler[1];
887 }
888 }
889
890 return $policyHandler ?: [$this, 'defaultPolicyHandler'];
891 }
892
893 protected function isPolicyHandlerParseable($policyHandler)
894 {
895 return (strpos($policyHandler, '@') === true
896 || strpos($policyHandler, '::') === true);
897 }
898
899 /**
900 * Default/Fallback policy handler for the route
901 *
902 * @return bool
903 */
904 public function defaultPolicyHandler()
905 {
906 return true;
907 }
908
909 /**
910 * Parse the rest and permission/policy handlers
911 *
912 * @param \WP_REST_Request $request
913 * @return null
914 * @throws \BadMethodCallException
915 */
916 public function prepareCallbacks($request)
917 {
918 $handler = $this->app->parseRestHandler(
919 $this->handler, $this->namespace
920 );
921
922 if ($handler instanceof Closure) {
923 $action = 'Closure';
924 $controller = null;
925 } else {
926 $handler = trim($handler, '\\');
927 $action = explode('@', $handler);
928 $pieces = explode('\\', $action[0]);
929 $controller = end($pieces);
930 }
931
932 try {
933 $policyHandler = $this->app->parsePolicyHandler(
934 $this->getPolicyHandler($this->policyHandler)
935 );
936
937 if ($policyHandler) {
938 $this->permissionHandler = $policyHandler;
939
940 // Adjust policy handler if the method was explicitly given
941 if (is_string($this->policyHandler)) {
942 if (is_array($policyHandler) && isset($policyHandler[1])) {
943 if ($pieces = explode('@', $this->policyHandler)) {
944 if (isset($pieces[1])) {
945 $this->permissionHandler[1] = $pieces[1];
946 }
947 }
948 }
949 }
950
951 if (!is_callable($this->permissionHandler)) {
952 throw new Exception;
953 }
954 }
955
956 } catch (Exception $e) {
957 $pHandler = $this->policyHandler;
958 if (is_array($this->permissionHandler) && $this->permissionHandler) {
959 $pHandler = is_object($this->permissionHandler[0]) ?
960 get_class($this->permissionHandler[0]) . ':' . $this->permissionHandler[1] :
961 $this->permissionHandler[0] . ':' . $this->permissionHandler[1];
962 }
963
964 throw new BadMethodCallException(
965 "The permission callback {$pHandler} is invalid or not callable."
966 );
967 }
968
969 if (is_array($policyHandler)) {
970 $policyHandler[0] = get_class($policyHandler[0]);
971 }
972
973 $this->actionInfo = [
974 'handler' => is_object($handler) ? $action : $handler,
975 'controller' => $controller,
976 'method' => is_array($action) ? $action[1] : null,
977 'path' => $this->uri,
978 'http_method' => $request->get_method(),
979 'full_uri' => $request->get_route(),
980 'permission_callback' => $policyHandler,
981 'compiled_url' => $this->compiled
982 ];
983
984
985 $this->action = $handler;
986
987 if ($routeParameters = $this->getParameter()) {
988 $this->substitutedParameters = $this->SubstituteParameters(
989 $routeParameters
990 );
991 }
992
993
994 return $this->action;
995 }
996
997 /**
998 * Get route one or more parameters
999 * @param string $key
1000 *
1001 * @return mixed
1002 */
1003 public function getParameter($key = null)
1004 {
1005 if (is_null($this->parameters)) {
1006 $this->parameters = $this->app->request->get_url_params();
1007 }
1008
1009 return $key ? $this->parameters[$key] : $this->parameters;
1010 }
1011
1012 /**
1013 * Dynamically access a route parameter.
1014 *
1015 * @param string $key
1016 * @return mixed
1017 */
1018 public function __get($key)
1019 {
1020 return $this->getParameter($key);
1021 }
1022 }
1023