1<?php 2 3namespace Illuminate\Routing; 4 5use Closure; 6use Illuminate\Container\Container; 7use Illuminate\Http\Exceptions\HttpResponseException; 8use Illuminate\Http\Request; 9use Illuminate\Routing\Contracts\ControllerDispatcher as ControllerDispatcherContract; 10use Illuminate\Routing\Matching\HostValidator; 11use Illuminate\Routing\Matching\MethodValidator; 12use Illuminate\Routing\Matching\SchemeValidator; 13use Illuminate\Routing\Matching\UriValidator; 14use Illuminate\Support\Arr; 15use Illuminate\Support\Str; 16use Illuminate\Support\Traits\Macroable; 17use LogicException; 18use Opis\Closure\SerializableClosure; 19use ReflectionFunction; 20use Symfony\Component\Routing\Route as SymfonyRoute; 21 22class Route 23{ 24 use CreatesRegularExpressionRouteConstraints, Macroable, RouteDependencyResolverTrait; 25 26 /** 27 * The URI pattern the route responds to. 28 * 29 * @var string 30 */ 31 public $uri; 32 33 /** 34 * The HTTP methods the route responds to. 35 * 36 * @var array 37 */ 38 public $methods; 39 40 /** 41 * The route action array. 42 * 43 * @var array 44 */ 45 public $action; 46 47 /** 48 * Indicates whether the route is a fallback route. 49 * 50 * @var bool 51 */ 52 public $isFallback = false; 53 54 /** 55 * The controller instance. 56 * 57 * @var mixed 58 */ 59 public $controller; 60 61 /** 62 * The default values for the route. 63 * 64 * @var array 65 */ 66 public $defaults = []; 67 68 /** 69 * The regular expression requirements. 70 * 71 * @var array 72 */ 73 public $wheres = []; 74 75 /** 76 * The array of matched parameters. 77 * 78 * @var array|null 79 */ 80 public $parameters; 81 82 /** 83 * The parameter names for the route. 84 * 85 * @var array|null 86 */ 87 public $parameterNames; 88 89 /** 90 * The array of the matched parameters' original values. 91 * 92 * @var array 93 */ 94 protected $originalParameters; 95 96 /** 97 * Indicates the maximum number of seconds the route should acquire a session lock for. 98 * 99 * @var int|null 100 */ 101 protected $lockSeconds; 102 103 /** 104 * Indicates the maximum number of seconds the route should wait while attempting to acquire a session lock. 105 * 106 * @var int|null 107 */ 108 protected $waitSeconds; 109 110 /** 111 * The computed gathered middleware. 112 * 113 * @var array|null 114 */ 115 public $computedMiddleware; 116 117 /** 118 * The compiled version of the route. 119 * 120 * @var \Symfony\Component\Routing\CompiledRoute 121 */ 122 public $compiled; 123 124 /** 125 * The router instance used by the route. 126 * 127 * @var \Illuminate\Routing\Router 128 */ 129 protected $router; 130 131 /** 132 * The container instance used by the route. 133 * 134 * @var \Illuminate\Container\Container 135 */ 136 protected $container; 137 138 /** 139 * The fields that implicit binding should use for a given parameter. 140 * 141 * @var array 142 */ 143 protected $bindingFields = []; 144 145 /** 146 * The validators used by the routes. 147 * 148 * @var array 149 */ 150 public static $validators; 151 152 /** 153 * Create a new Route instance. 154 * 155 * @param array|string $methods 156 * @param string $uri 157 * @param \Closure|array $action 158 * @return void 159 */ 160 public function __construct($methods, $uri, $action) 161 { 162 $this->uri = $uri; 163 $this->methods = (array) $methods; 164 $this->action = Arr::except($this->parseAction($action), ['prefix']); 165 166 if (in_array('GET', $this->methods) && ! in_array('HEAD', $this->methods)) { 167 $this->methods[] = 'HEAD'; 168 } 169 170 $this->prefix(is_array($action) ? Arr::get($action, 'prefix') : ''); 171 } 172 173 /** 174 * Parse the route action into a standard array. 175 * 176 * @param callable|array|null $action 177 * @return array 178 * 179 * @throws \UnexpectedValueException 180 */ 181 protected function parseAction($action) 182 { 183 return RouteAction::parse($this->uri, $action); 184 } 185 186 /** 187 * Run the route action and return the response. 188 * 189 * @return mixed 190 */ 191 public function run() 192 { 193 $this->container = $this->container ?: new Container; 194 195 try { 196 if ($this->isControllerAction()) { 197 return $this->runController(); 198 } 199 200 return $this->runCallable(); 201 } catch (HttpResponseException $e) { 202 return $e->getResponse(); 203 } 204 } 205 206 /** 207 * Checks whether the route's action is a controller. 208 * 209 * @return bool 210 */ 211 protected function isControllerAction() 212 { 213 return is_string($this->action['uses']) && ! $this->isSerializedClosure(); 214 } 215 216 /** 217 * Run the route action and return the response. 218 * 219 * @return mixed 220 */ 221 protected function runCallable() 222 { 223 $callable = $this->action['uses']; 224 225 if ($this->isSerializedClosure()) { 226 $callable = unserialize($this->action['uses'])->getClosure(); 227 } 228 229 return $callable(...array_values($this->resolveMethodDependencies( 230 $this->parametersWithoutNulls(), new ReflectionFunction($callable) 231 ))); 232 } 233 234 /** 235 * Determine if the route action is a serialized Closure. 236 * 237 * @return bool 238 */ 239 protected function isSerializedClosure() 240 { 241 return RouteAction::containsSerializedClosure($this->action); 242 } 243 244 /** 245 * Run the route action and return the response. 246 * 247 * @return mixed 248 * 249 * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException 250 */ 251 protected function runController() 252 { 253 return $this->controllerDispatcher()->dispatch( 254 $this, $this->getController(), $this->getControllerMethod() 255 ); 256 } 257 258 /** 259 * Get the controller instance for the route. 260 * 261 * @return mixed 262 */ 263 public function getController() 264 { 265 if (! $this->controller) { 266 $class = $this->parseControllerCallback()[0]; 267 268 $this->controller = $this->container->make(ltrim($class, '\\')); 269 } 270 271 return $this->controller; 272 } 273 274 /** 275 * Get the controller method used for the route. 276 * 277 * @return string 278 */ 279 protected function getControllerMethod() 280 { 281 return $this->parseControllerCallback()[1]; 282 } 283 284 /** 285 * Parse the controller. 286 * 287 * @return array 288 */ 289 protected function parseControllerCallback() 290 { 291 return Str::parseCallback($this->action['uses']); 292 } 293 294 /** 295 * Determine if the route matches a given request. 296 * 297 * @param \Illuminate\Http\Request $request 298 * @param bool $includingMethod 299 * @return bool 300 */ 301 public function matches(Request $request, $includingMethod = true) 302 { 303 $this->compileRoute(); 304 305 foreach (self::getValidators() as $validator) { 306 if (! $includingMethod && $validator instanceof MethodValidator) { 307 continue; 308 } 309 310 if (! $validator->matches($this, $request)) { 311 return false; 312 } 313 } 314 315 return true; 316 } 317 318 /** 319 * Compile the route into a Symfony CompiledRoute instance. 320 * 321 * @return \Symfony\Component\Routing\CompiledRoute 322 */ 323 protected function compileRoute() 324 { 325 if (! $this->compiled) { 326 $this->compiled = $this->toSymfonyRoute()->compile(); 327 } 328 329 return $this->compiled; 330 } 331 332 /** 333 * Bind the route to a given request for execution. 334 * 335 * @param \Illuminate\Http\Request $request 336 * @return $this 337 */ 338 public function bind(Request $request) 339 { 340 $this->compileRoute(); 341 342 $this->parameters = (new RouteParameterBinder($this)) 343 ->parameters($request); 344 345 $this->originalParameters = $this->parameters; 346 347 return $this; 348 } 349 350 /** 351 * Determine if the route has parameters. 352 * 353 * @return bool 354 */ 355 public function hasParameters() 356 { 357 return isset($this->parameters); 358 } 359 360 /** 361 * Determine a given parameter exists from the route. 362 * 363 * @param string $name 364 * @return bool 365 */ 366 public function hasParameter($name) 367 { 368 if ($this->hasParameters()) { 369 return array_key_exists($name, $this->parameters()); 370 } 371 372 return false; 373 } 374 375 /** 376 * Get a given parameter from the route. 377 * 378 * @param string $name 379 * @param string|object|null $default 380 * @return string|object|null 381 */ 382 public function parameter($name, $default = null) 383 { 384 return Arr::get($this->parameters(), $name, $default); 385 } 386 387 /** 388 * Get original value of a given parameter from the route. 389 * 390 * @param string $name 391 * @param string|null $default 392 * @return string|null 393 */ 394 public function originalParameter($name, $default = null) 395 { 396 return Arr::get($this->originalParameters(), $name, $default); 397 } 398 399 /** 400 * Set a parameter to the given value. 401 * 402 * @param string $name 403 * @param string|object|null $value 404 * @return void 405 */ 406 public function setParameter($name, $value) 407 { 408 $this->parameters(); 409 410 $this->parameters[$name] = $value; 411 } 412 413 /** 414 * Unset a parameter on the route if it is set. 415 * 416 * @param string $name 417 * @return void 418 */ 419 public function forgetParameter($name) 420 { 421 $this->parameters(); 422 423 unset($this->parameters[$name]); 424 } 425 426 /** 427 * Get the key / value list of parameters for the route. 428 * 429 * @return array 430 * 431 * @throws \LogicException 432 */ 433 public function parameters() 434 { 435 if (isset($this->parameters)) { 436 return $this->parameters; 437 } 438 439 throw new LogicException('Route is not bound.'); 440 } 441 442 /** 443 * Get the key / value list of original parameters for the route. 444 * 445 * @return array 446 * 447 * @throws \LogicException 448 */ 449 public function originalParameters() 450 { 451 if (isset($this->originalParameters)) { 452 return $this->originalParameters; 453 } 454 455 throw new LogicException('Route is not bound.'); 456 } 457 458 /** 459 * Get the key / value list of parameters without null values. 460 * 461 * @return array 462 */ 463 public function parametersWithoutNulls() 464 { 465 return array_filter($this->parameters(), function ($p) { 466 return ! is_null($p); 467 }); 468 } 469 470 /** 471 * Get all of the parameter names for the route. 472 * 473 * @return array 474 */ 475 public function parameterNames() 476 { 477 if (isset($this->parameterNames)) { 478 return $this->parameterNames; 479 } 480 481 return $this->parameterNames = $this->compileParameterNames(); 482 } 483 484 /** 485 * Get the parameter names for the route. 486 * 487 * @return array 488 */ 489 protected function compileParameterNames() 490 { 491 preg_match_all('/\{(.*?)\}/', $this->getDomain().$this->uri, $matches); 492 493 return array_map(function ($m) { 494 return trim($m, '?'); 495 }, $matches[1]); 496 } 497 498 /** 499 * Get the parameters that are listed in the route / controller signature. 500 * 501 * @param string|null $subClass 502 * @return array 503 */ 504 public function signatureParameters($subClass = null) 505 { 506 return RouteSignatureParameters::fromAction($this->action, $subClass); 507 } 508 509 /** 510 * Get the binding field for the given parameter. 511 * 512 * @param string|int $parameter 513 * @return string|null 514 */ 515 public function bindingFieldFor($parameter) 516 { 517 $fields = is_int($parameter) ? array_values($this->bindingFields) : $this->bindingFields; 518 519 return $fields[$parameter] ?? null; 520 } 521 522 /** 523 * Get the binding fields for the route. 524 * 525 * @return array 526 */ 527 public function bindingFields() 528 { 529 return $this->bindingFields ?? []; 530 } 531 532 /** 533 * Set the binding fields for the route. 534 * 535 * @param array $bindingFields 536 * @return $this 537 */ 538 public function setBindingFields(array $bindingFields) 539 { 540 $this->bindingFields = $bindingFields; 541 542 return $this; 543 } 544 545 /** 546 * Get the parent parameter of the given parameter. 547 * 548 * @param string $parameter 549 * @return string 550 */ 551 public function parentOfParameter($parameter) 552 { 553 $key = array_search($parameter, array_keys($this->parameters)); 554 555 if ($key === 0) { 556 return; 557 } 558 559 return array_values($this->parameters)[$key - 1]; 560 } 561 562 /** 563 * Set a default value for the route. 564 * 565 * @param string $key 566 * @param mixed $value 567 * @return $this 568 */ 569 public function defaults($key, $value) 570 { 571 $this->defaults[$key] = $value; 572 573 return $this; 574 } 575 576 /** 577 * Set the default values for the route. 578 * 579 * @param array $defaults 580 * @return $this 581 */ 582 public function setDefaults(array $defaults) 583 { 584 $this->defaults = $defaults; 585 586 return $this; 587 } 588 589 /** 590 * Set a regular expression requirement on the route. 591 * 592 * @param array|string $name 593 * @param string|null $expression 594 * @return $this 595 */ 596 public function where($name, $expression = null) 597 { 598 foreach ($this->parseWhere($name, $expression) as $name => $expression) { 599 $this->wheres[$name] = $expression; 600 } 601 602 return $this; 603 } 604 605 /** 606 * Parse arguments to the where method into an array. 607 * 608 * @param array|string $name 609 * @param string $expression 610 * @return array 611 */ 612 protected function parseWhere($name, $expression) 613 { 614 return is_array($name) ? $name : [$name => $expression]; 615 } 616 617 /** 618 * Set a list of regular expression requirements on the route. 619 * 620 * @param array $wheres 621 * @return $this 622 */ 623 public function setWheres(array $wheres) 624 { 625 foreach ($wheres as $name => $expression) { 626 $this->where($name, $expression); 627 } 628 629 return $this; 630 } 631 632 /** 633 * Mark this route as a fallback route. 634 * 635 * @return $this 636 */ 637 public function fallback() 638 { 639 $this->isFallback = true; 640 641 return $this; 642 } 643 644 /** 645 * Set the fallback value. 646 * 647 * @param bool $isFallback 648 * @return $this 649 */ 650 public function setFallback($isFallback) 651 { 652 $this->isFallback = $isFallback; 653 654 return $this; 655 } 656 657 /** 658 * Get the HTTP verbs the route responds to. 659 * 660 * @return array 661 */ 662 public function methods() 663 { 664 return $this->methods; 665 } 666 667 /** 668 * Determine if the route only responds to HTTP requests. 669 * 670 * @return bool 671 */ 672 public function httpOnly() 673 { 674 return in_array('http', $this->action, true); 675 } 676 677 /** 678 * Determine if the route only responds to HTTPS requests. 679 * 680 * @return bool 681 */ 682 public function httpsOnly() 683 { 684 return $this->secure(); 685 } 686 687 /** 688 * Determine if the route only responds to HTTPS requests. 689 * 690 * @return bool 691 */ 692 public function secure() 693 { 694 return in_array('https', $this->action, true); 695 } 696 697 /** 698 * Get or set the domain for the route. 699 * 700 * @param string|null $domain 701 * @return $this|string|null 702 */ 703 public function domain($domain = null) 704 { 705 if (is_null($domain)) { 706 return $this->getDomain(); 707 } 708 709 $parsed = RouteUri::parse($domain); 710 711 $this->action['domain'] = $parsed->uri; 712 713 $this->bindingFields = array_merge( 714 $this->bindingFields, $parsed->bindingFields 715 ); 716 717 return $this; 718 } 719 720 /** 721 * Get the domain defined for the route. 722 * 723 * @return string|null 724 */ 725 public function getDomain() 726 { 727 return isset($this->action['domain']) 728 ? str_replace(['http://', 'https://'], '', $this->action['domain']) : null; 729 } 730 731 /** 732 * Get the prefix of the route instance. 733 * 734 * @return string|null 735 */ 736 public function getPrefix() 737 { 738 return $this->action['prefix'] ?? null; 739 } 740 741 /** 742 * Add a prefix to the route URI. 743 * 744 * @param string $prefix 745 * @return $this 746 */ 747 public function prefix($prefix) 748 { 749 $prefix = $prefix ?? ''; 750 751 $this->updatePrefixOnAction($prefix); 752 753 $uri = rtrim($prefix, '/').'/'.ltrim($this->uri, '/'); 754 755 return $this->setUri($uri !== '/' ? trim($uri, '/') : $uri); 756 } 757 758 /** 759 * Update the "prefix" attribute on the action array. 760 * 761 * @param string $prefix 762 * @return void 763 */ 764 protected function updatePrefixOnAction($prefix) 765 { 766 if (! empty($newPrefix = trim(rtrim($prefix, '/').'/'.ltrim($this->action['prefix'] ?? '', '/'), '/'))) { 767 $this->action['prefix'] = $newPrefix; 768 } 769 } 770 771 /** 772 * Get the URI associated with the route. 773 * 774 * @return string 775 */ 776 public function uri() 777 { 778 return $this->uri; 779 } 780 781 /** 782 * Set the URI that the route responds to. 783 * 784 * @param string $uri 785 * @return $this 786 */ 787 public function setUri($uri) 788 { 789 $this->uri = $this->parseUri($uri); 790 791 return $this; 792 } 793 794 /** 795 * Parse the route URI and normalize / store any implicit binding fields. 796 * 797 * @param string $uri 798 * @return string 799 */ 800 protected function parseUri($uri) 801 { 802 $this->bindingFields = []; 803 804 return tap(RouteUri::parse($uri), function ($uri) { 805 $this->bindingFields = $uri->bindingFields; 806 })->uri; 807 } 808 809 /** 810 * Get the name of the route instance. 811 * 812 * @return string|null 813 */ 814 public function getName() 815 { 816 return $this->action['as'] ?? null; 817 } 818 819 /** 820 * Add or change the route name. 821 * 822 * @param string $name 823 * @return $this 824 */ 825 public function name($name) 826 { 827 $this->action['as'] = isset($this->action['as']) ? $this->action['as'].$name : $name; 828 829 return $this; 830 } 831 832 /** 833 * Determine whether the route's name matches the given patterns. 834 * 835 * @param mixed ...$patterns 836 * @return bool 837 */ 838 public function named(...$patterns) 839 { 840 if (is_null($routeName = $this->getName())) { 841 return false; 842 } 843 844 foreach ($patterns as $pattern) { 845 if (Str::is($pattern, $routeName)) { 846 return true; 847 } 848 } 849 850 return false; 851 } 852 853 /** 854 * Set the handler for the route. 855 * 856 * @param \Closure|array|string $action 857 * @return $this 858 */ 859 public function uses($action) 860 { 861 if (is_array($action)) { 862 $action = $action[0].'@'.$action[1]; 863 } 864 865 $action = is_string($action) ? $this->addGroupNamespaceToStringUses($action) : $action; 866 867 return $this->setAction(array_merge($this->action, $this->parseAction([ 868 'uses' => $action, 869 'controller' => $action, 870 ]))); 871 } 872 873 /** 874 * Parse a string based action for the "uses" fluent method. 875 * 876 * @param string $action 877 * @return string 878 */ 879 protected function addGroupNamespaceToStringUses($action) 880 { 881 $groupStack = last($this->router->getGroupStack()); 882 883 if (isset($groupStack['namespace']) && strpos($action, '\\') !== 0) { 884 return $groupStack['namespace'].'\\'.$action; 885 } 886 887 return $action; 888 } 889 890 /** 891 * Get the action name for the route. 892 * 893 * @return string 894 */ 895 public function getActionName() 896 { 897 return $this->action['controller'] ?? 'Closure'; 898 } 899 900 /** 901 * Get the method name of the route action. 902 * 903 * @return string 904 */ 905 public function getActionMethod() 906 { 907 return Arr::last(explode('@', $this->getActionName())); 908 } 909 910 /** 911 * Get the action array or one of its properties for the route. 912 * 913 * @param string|null $key 914 * @return mixed 915 */ 916 public function getAction($key = null) 917 { 918 return Arr::get($this->action, $key); 919 } 920 921 /** 922 * Set the action array for the route. 923 * 924 * @param array $action 925 * @return $this 926 */ 927 public function setAction(array $action) 928 { 929 $this->action = $action; 930 931 if (isset($this->action['domain'])) { 932 $this->domain($this->action['domain']); 933 } 934 935 return $this; 936 } 937 938 /** 939 * Get the value of the action that should be taken on a missing model exception. 940 * 941 * @return \Closure|null 942 */ 943 public function getMissing() 944 { 945 $missing = $this->action['missing'] ?? null; 946 947 return is_string($missing) && 948 Str::startsWith($missing, 'C:32:"Opis\\Closure\\SerializableClosure') 949 ? unserialize($missing) 950 : $missing; 951 } 952 953 /** 954 * Define the callable that should be invoked on a missing model exception. 955 * 956 * @param \Closure $missing 957 * @return $this 958 */ 959 public function missing($missing) 960 { 961 $this->action['missing'] = $missing; 962 963 return $this; 964 } 965 966 /** 967 * Get all middleware, including the ones from the controller. 968 * 969 * @return array 970 */ 971 public function gatherMiddleware() 972 { 973 if (! is_null($this->computedMiddleware)) { 974 return $this->computedMiddleware; 975 } 976 977 $this->computedMiddleware = []; 978 979 return $this->computedMiddleware = Router::uniqueMiddleware(array_merge( 980 $this->middleware(), $this->controllerMiddleware() 981 )); 982 } 983 984 /** 985 * Get or set the middlewares attached to the route. 986 * 987 * @param array|string|null $middleware 988 * @return $this|array 989 */ 990 public function middleware($middleware = null) 991 { 992 if (is_null($middleware)) { 993 return (array) ($this->action['middleware'] ?? []); 994 } 995 996 if (is_string($middleware)) { 997 $middleware = func_get_args(); 998 } 999 1000 $this->action['middleware'] = array_merge( 1001 (array) ($this->action['middleware'] ?? []), $middleware 1002 ); 1003 1004 return $this; 1005 } 1006 1007 /** 1008 * Get the middleware for the route's controller. 1009 * 1010 * @return array 1011 */ 1012 public function controllerMiddleware() 1013 { 1014 if (! $this->isControllerAction()) { 1015 return []; 1016 } 1017 1018 return $this->controllerDispatcher()->getMiddleware( 1019 $this->getController(), $this->getControllerMethod() 1020 ); 1021 } 1022 1023 /** 1024 * Specify middleware that should be removed from the given route. 1025 * 1026 * @param array|string $middleware 1027 * @return $this|array 1028 */ 1029 public function withoutMiddleware($middleware) 1030 { 1031 $this->action['excluded_middleware'] = array_merge( 1032 (array) ($this->action['excluded_middleware'] ?? []), Arr::wrap($middleware) 1033 ); 1034 1035 return $this; 1036 } 1037 1038 /** 1039 * Get the middleware should be removed from the route. 1040 * 1041 * @return array 1042 */ 1043 public function excludedMiddleware() 1044 { 1045 return (array) ($this->action['excluded_middleware'] ?? []); 1046 } 1047 1048 /** 1049 * Specify that the route should not allow concurrent requests from the same session. 1050 * 1051 * @param int|null $lockSeconds 1052 * @param int|null $waitSeconds 1053 * @return $this 1054 */ 1055 public function block($lockSeconds = 10, $waitSeconds = 10) 1056 { 1057 $this->lockSeconds = $lockSeconds; 1058 $this->waitSeconds = $waitSeconds; 1059 1060 return $this; 1061 } 1062 1063 /** 1064 * Specify that the route should allow concurrent requests from the same session. 1065 * 1066 * @return $this 1067 */ 1068 public function withoutBlocking() 1069 { 1070 return $this->block(null, null); 1071 } 1072 1073 /** 1074 * Get the maximum number of seconds the route's session lock should be held for. 1075 * 1076 * @return int|null 1077 */ 1078 public function locksFor() 1079 { 1080 return $this->lockSeconds; 1081 } 1082 1083 /** 1084 * Get the maximum number of seconds to wait while attempting to acquire a session lock. 1085 * 1086 * @return int|null 1087 */ 1088 public function waitsFor() 1089 { 1090 return $this->waitSeconds; 1091 } 1092 1093 /** 1094 * Get the dispatcher for the route's controller. 1095 * 1096 * @return \Illuminate\Routing\Contracts\ControllerDispatcher 1097 */ 1098 public function controllerDispatcher() 1099 { 1100 if ($this->container->bound(ControllerDispatcherContract::class)) { 1101 return $this->container->make(ControllerDispatcherContract::class); 1102 } 1103 1104 return new ControllerDispatcher($this->container); 1105 } 1106 1107 /** 1108 * Get the route validators for the instance. 1109 * 1110 * @return array 1111 */ 1112 public static function getValidators() 1113 { 1114 if (isset(static::$validators)) { 1115 return static::$validators; 1116 } 1117 1118 // To match the route, we will use a chain of responsibility pattern with the 1119 // validator implementations. We will spin through each one making sure it 1120 // passes and then we will know if the route as a whole matches request. 1121 return static::$validators = [ 1122 new UriValidator, new MethodValidator, 1123 new SchemeValidator, new HostValidator, 1124 ]; 1125 } 1126 1127 /** 1128 * Convert the route to a Symfony route. 1129 * 1130 * @return \Symfony\Component\Routing\Route 1131 */ 1132 public function toSymfonyRoute() 1133 { 1134 return new SymfonyRoute( 1135 preg_replace('/\{(\w+?)\?\}/', '{$1}', $this->uri()), $this->getOptionalParameterNames(), 1136 $this->wheres, ['utf8' => true, 'action' => $this->action], 1137 $this->getDomain() ?: '', [], $this->methods 1138 ); 1139 } 1140 1141 /** 1142 * Get the optional parameter names for the route. 1143 * 1144 * @return array 1145 */ 1146 protected function getOptionalParameterNames() 1147 { 1148 preg_match_all('/\{(\w+?)\?\}/', $this->uri(), $matches); 1149 1150 return isset($matches[1]) ? array_fill_keys($matches[1], null) : []; 1151 } 1152 1153 /** 1154 * Get the compiled version of the route. 1155 * 1156 * @return \Symfony\Component\Routing\CompiledRoute 1157 */ 1158 public function getCompiled() 1159 { 1160 return $this->compiled; 1161 } 1162 1163 /** 1164 * Set the router instance on the route. 1165 * 1166 * @param \Illuminate\Routing\Router $router 1167 * @return $this 1168 */ 1169 public function setRouter(Router $router) 1170 { 1171 $this->router = $router; 1172 1173 return $this; 1174 } 1175 1176 /** 1177 * Set the container instance on the route. 1178 * 1179 * @param \Illuminate\Container\Container $container 1180 * @return $this 1181 */ 1182 public function setContainer(Container $container) 1183 { 1184 $this->container = $container; 1185 1186 return $this; 1187 } 1188 1189 /** 1190 * Prepare the route instance for serialization. 1191 * 1192 * @return void 1193 * 1194 * @throws \LogicException 1195 */ 1196 public function prepareForSerialization() 1197 { 1198 if ($this->action['uses'] instanceof Closure) { 1199 $this->action['uses'] = serialize(new SerializableClosure($this->action['uses'])); 1200 } 1201 1202 if (isset($this->action['missing']) && $this->action['missing'] instanceof Closure) { 1203 $this->action['missing'] = serialize(new SerializableClosure($this->action['missing'])); 1204 } 1205 1206 $this->compileRoute(); 1207 1208 unset($this->router, $this->container); 1209 } 1210 1211 /** 1212 * Dynamically access route parameters. 1213 * 1214 * @param string $key 1215 * @return mixed 1216 */ 1217 public function __get($key) 1218 { 1219 return $this->parameter($key); 1220 } 1221} 1222