/Front_End/vendor/laravel/framework/src/Illuminate/Routing/Route.php
PHP | 942 lines | 407 code | 126 blank | 409 comment | 30 complexity | 15adc465241c517e19bd381ef1c655a2 MD5 | raw file
- <?php
- namespace Illuminate\Routing;
- use Closure;
- use LogicException;
- use ReflectionMethod;
- use ReflectionFunction;
- use Illuminate\Support\Arr;
- use Illuminate\Support\Str;
- use Illuminate\Http\Request;
- use UnexpectedValueException;
- use Illuminate\Container\Container;
- use Illuminate\Routing\Matching\UriValidator;
- use Illuminate\Routing\Matching\HostValidator;
- use Illuminate\Routing\Matching\MethodValidator;
- use Illuminate\Routing\Matching\SchemeValidator;
- use Symfony\Component\Routing\Route as SymfonyRoute;
- use Illuminate\Http\Exception\HttpResponseException;
- class Route
- {
- use RouteDependencyResolverTrait;
- /**
- * The URI pattern the route responds to.
- *
- * @var string
- */
- protected $uri;
- /**
- * The HTTP methods the route responds to.
- *
- * @var array
- */
- protected $methods;
- /**
- * The route action array.
- *
- * @var array
- */
- protected $action;
- /**
- * The default values for the route.
- *
- * @var array
- */
- protected $defaults = [];
- /**
- * The regular expression requirements.
- *
- * @var array
- */
- protected $wheres = [];
- /**
- * The array of matched parameters.
- *
- * @var array
- */
- protected $parameters;
- /**
- * The parameter names for the route.
- *
- * @var array|null
- */
- protected $parameterNames;
- /**
- * The compiled version of the route.
- *
- * @var \Symfony\Component\Routing\CompiledRoute
- */
- protected $compiled;
- /**
- * The router instance used by the route.
- *
- * @var \Illuminate\Routing\Router
- */
- protected $router;
- /**
- * The container instance used by the route.
- *
- * @var \Illuminate\Container\Container
- */
- protected $container;
- /**
- * The validators used by the routes.
- *
- * @var array
- */
- public static $validators;
- /**
- * Create a new Route instance.
- *
- * @param array|string $methods
- * @param string $uri
- * @param \Closure|array $action
- * @return void
- */
- public function __construct($methods, $uri, $action)
- {
- $this->uri = $uri;
- $this->methods = (array) $methods;
- $this->action = $this->parseAction($action);
- if (in_array('GET', $this->methods) && ! in_array('HEAD', $this->methods)) {
- $this->methods[] = 'HEAD';
- }
- if (isset($this->action['prefix'])) {
- $this->prefix($this->action['prefix']);
- }
- }
- /**
- * Run the route action and return the response.
- *
- * @param \Illuminate\Http\Request $request
- * @return mixed
- */
- public function run(Request $request)
- {
- $this->container = $this->container ?: new Container;
- try {
- if (! is_string($this->action['uses'])) {
- return $this->runCallable($request);
- }
- return $this->runController($request);
- } catch (HttpResponseException $e) {
- return $e->getResponse();
- }
- }
- /**
- * Run the route action and return the response.
- *
- * @param \Illuminate\Http\Request $request
- * @return mixed
- */
- protected function runCallable(Request $request)
- {
- $parameters = $this->resolveMethodDependencies(
- $this->parametersWithoutNulls(), new ReflectionFunction($this->action['uses'])
- );
- return call_user_func_array($this->action['uses'], $parameters);
- }
- /**
- * Run the route action and return the response.
- *
- * @param \Illuminate\Http\Request $request
- * @return mixed
- *
- * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
- */
- protected function runController(Request $request)
- {
- list($class, $method) = explode('@', $this->action['uses']);
- return (new ControllerDispatcher($this->router, $this->container))
- ->dispatch($this, $request, $class, $method);
- }
- /**
- * Determine if the route matches given request.
- *
- * @param \Illuminate\Http\Request $request
- * @param bool $includingMethod
- * @return bool
- */
- public function matches(Request $request, $includingMethod = true)
- {
- $this->compileRoute();
- foreach ($this->getValidators() as $validator) {
- if (! $includingMethod && $validator instanceof MethodValidator) {
- continue;
- }
- if (! $validator->matches($this, $request)) {
- return false;
- }
- }
- return true;
- }
- /**
- * Compile the route into a Symfony CompiledRoute instance.
- *
- * @return void
- */
- protected function compileRoute()
- {
- $optionals = $this->extractOptionalParameters();
- $uri = preg_replace('/\{(\w+?)\?\}/', '{$1}', $this->uri);
- $this->compiled = (
- new SymfonyRoute($uri, $optionals, $this->wheres, [], $this->domain() ?: '')
- )->compile();
- }
- /**
- * Get the optional parameters for the route.
- *
- * @return array
- */
- protected function extractOptionalParameters()
- {
- preg_match_all('/\{(\w+?)\?\}/', $this->uri, $matches);
- return isset($matches[1]) ? array_fill_keys($matches[1], null) : [];
- }
- /**
- * Get or set the middlewares attached to the route.
- *
- * @param array|string|null $middleware
- * @return $this|array
- */
- public function middleware($middleware = null)
- {
- if (is_null($middleware)) {
- return (array) Arr::get($this->action, 'middleware', []);
- }
- if (is_string($middleware)) {
- $middleware = [$middleware];
- }
- $this->action['middleware'] = array_merge(
- (array) Arr::get($this->action, 'middleware', []), $middleware
- );
- return $this;
- }
- /**
- * Get the controller middleware for the route.
- *
- * @return array
- */
- protected function controllerMiddleware()
- {
- list($class, $method) = explode('@', $this->action['uses']);
- $controller = $this->container->make($class);
- return (new ControllerDispatcher($this->router, $this->container))
- ->getMiddleware($controller, $method);
- }
- /**
- * Get the parameters that are listed in the route / controller signature.
- *
- * @param string|null $subClass
- * @return array
- */
- public function signatureParameters($subClass = null)
- {
- $action = $this->getAction();
- if (is_string($action['uses'])) {
- list($class, $method) = explode('@', $action['uses']);
- $parameters = (new ReflectionMethod($class, $method))->getParameters();
- } else {
- $parameters = (new ReflectionFunction($action['uses']))->getParameters();
- }
- return is_null($subClass) ? $parameters : array_filter($parameters, function ($p) use ($subClass) {
- return $p->getClass() && $p->getClass()->isSubclassOf($subClass);
- });
- }
- /**
- * Determine if the route has parameters.
- *
- * @return bool
- */
- public function hasParameters()
- {
- return isset($this->parameters);
- }
- /**
- * Determine a given parameter exists from the route.
- *
- * @param string $name
- * @return bool
- */
- public function hasParameter($name)
- {
- if (! $this->hasParameters()) {
- return false;
- }
- return array_key_exists($name, $this->parameters());
- }
- /**
- * Get a given parameter from the route.
- *
- * @param string $name
- * @param mixed $default
- * @return string|object
- */
- public function getParameter($name, $default = null)
- {
- return $this->parameter($name, $default);
- }
- /**
- * Get a given parameter from the route.
- *
- * @param string $name
- * @param mixed $default
- * @return string|object
- */
- public function parameter($name, $default = null)
- {
- return Arr::get($this->parameters(), $name, $default);
- }
- /**
- * Set a parameter to the given value.
- *
- * @param string $name
- * @param mixed $value
- * @return void
- */
- public function setParameter($name, $value)
- {
- $this->parameters();
- $this->parameters[$name] = $value;
- }
- /**
- * Unset a parameter on the route if it is set.
- *
- * @param string $name
- * @return void
- */
- public function forgetParameter($name)
- {
- $this->parameters();
- unset($this->parameters[$name]);
- }
- /**
- * Get the key / value list of parameters for the route.
- *
- * @return array
- *
- * @throws \LogicException
- */
- public function parameters()
- {
- if (isset($this->parameters)) {
- return $this->parameters;
- }
- throw new LogicException('Route is not bound.');
- }
- /**
- * Get the key / value list of parameters without null values.
- *
- * @return array
- */
- public function parametersWithoutNulls()
- {
- return array_filter($this->parameters(), function ($p) {
- return ! is_null($p);
- });
- }
- /**
- * Get all of the parameter names for the route.
- *
- * @return array
- */
- public function parameterNames()
- {
- if (isset($this->parameterNames)) {
- return $this->parameterNames;
- }
- return $this->parameterNames = $this->compileParameterNames();
- }
- /**
- * Get the parameter names for the route.
- *
- * @return array
- */
- protected function compileParameterNames()
- {
- preg_match_all('/\{(.*?)\}/', $this->domain().$this->uri, $matches);
- return array_map(function ($m) {
- return trim($m, '?');
- }, $matches[1]);
- }
- /**
- * Bind the route to a given request for execution.
- *
- * @param \Illuminate\Http\Request $request
- * @return $this
- */
- public function bind(Request $request)
- {
- $this->compileRoute();
- $this->bindParameters($request);
- return $this;
- }
- /**
- * Extract the parameter list from the request.
- *
- * @param \Illuminate\Http\Request $request
- * @return array
- */
- public function bindParameters(Request $request)
- {
- // If the route has a regular expression for the host part of the URI, we will
- // compile that and get the parameter matches for this domain. We will then
- // merge them into this parameters array so that this array is completed.
- $params = $this->matchToKeys(
- array_slice($this->bindPathParameters($request), 1)
- );
- // If the route has a regular expression for the host part of the URI, we will
- // compile that and get the parameter matches for this domain. We will then
- // merge them into this parameters array so that this array is completed.
- if (! is_null($this->compiled->getHostRegex())) {
- $params = $this->bindHostParameters(
- $request, $params
- );
- }
- return $this->parameters = $this->replaceDefaults($params);
- }
- /**
- * Get the parameter matches for the path portion of the URI.
- *
- * @param \Illuminate\Http\Request $request
- * @return array
- */
- protected function bindPathParameters(Request $request)
- {
- preg_match($this->compiled->getRegex(), '/'.$request->decodedPath(), $matches);
- return $matches;
- }
- /**
- * Extract the parameter list from the host part of the request.
- *
- * @param \Illuminate\Http\Request $request
- * @param array $parameters
- * @return array
- */
- protected function bindHostParameters(Request $request, $parameters)
- {
- preg_match($this->compiled->getHostRegex(), $request->getHost(), $matches);
- return array_merge($this->matchToKeys(array_slice($matches, 1)), $parameters);
- }
- /**
- * Combine a set of parameter matches with the route's keys.
- *
- * @param array $matches
- * @return array
- */
- protected function matchToKeys(array $matches)
- {
- if (empty($parameterNames = $this->parameterNames())) {
- return [];
- }
- $parameters = array_intersect_key($matches, array_flip($parameterNames));
- return array_filter($parameters, function ($value) {
- return is_string($value) && strlen($value) > 0;
- });
- }
- /**
- * Replace null parameters with their defaults.
- *
- * @param array $parameters
- * @return array
- */
- protected function replaceDefaults(array $parameters)
- {
- foreach ($parameters as $key => $value) {
- $parameters[$key] = isset($value) ? $value : Arr::get($this->defaults, $key);
- }
- foreach ($this->defaults as $key => $value) {
- if (! isset($parameters[$key])) {
- $parameters[$key] = $value;
- }
- }
- return $parameters;
- }
- /**
- * Parse the route action into a standard array.
- *
- * @param callable|array|null $action
- * @return array
- *
- * @throws \UnexpectedValueException
- */
- protected function parseAction($action)
- {
- // If no action is passed in right away, we assume the user will make use of
- // fluent routing. In that case, we set a default closure, to be executed
- // if the user never explicitly sets an action to handle the given uri.
- if (is_null($action)) {
- return ['uses' => function () {
- throw new LogicException("Route for [{$this->uri}] has no action.");
- }];
- }
- // If the action is already a Closure instance, we will just set that instance
- // as the "uses" property, because there is nothing else we need to do when
- // it is available. Otherwise we will need to find it in the action list.
- if (is_callable($action)) {
- return ['uses' => $action];
- }
- // If no "uses" property has been set, we will dig through the array to find a
- // Closure instance within this list. We will set the first Closure we come
- // across into the "uses" property that will get fired off by this route.
- elseif (! isset($action['uses'])) {
- $action['uses'] = $this->findCallable($action);
- }
- if (is_string($action['uses']) && ! Str::contains($action['uses'], '@')) {
- throw new UnexpectedValueException(sprintf(
- 'Invalid route action: [%s]', $action['uses']
- ));
- }
- return $action;
- }
- /**
- * Find the callable in an action array.
- *
- * @param array $action
- * @return callable
- */
- protected function findCallable(array $action)
- {
- return Arr::first($action, function ($key, $value) {
- return is_callable($value) && is_numeric($key);
- });
- }
- /**
- * Get the route validators for the instance.
- *
- * @return array
- */
- public static function getValidators()
- {
- if (isset(static::$validators)) {
- return static::$validators;
- }
- // To match the route, we will use a chain of responsibility pattern with the
- // validator implementations. We will spin through each one making sure it
- // passes and then we will know if the route as a whole matches request.
- return static::$validators = [
- new MethodValidator, new SchemeValidator,
- new HostValidator, new UriValidator,
- ];
- }
- /**
- * Set a default value for the route.
- *
- * @param string $key
- * @param mixed $value
- * @return $this
- */
- public function defaults($key, $value)
- {
- $this->defaults[$key] = $value;
- return $this;
- }
- /**
- * Set a regular expression requirement on the route.
- *
- * @param array|string $name
- * @param string $expression
- * @return $this
- */
- public function where($name, $expression = null)
- {
- foreach ($this->parseWhere($name, $expression) as $name => $expression) {
- $this->wheres[$name] = $expression;
- }
- return $this;
- }
- /**
- * Parse arguments to the where method into an array.
- *
- * @param array|string $name
- * @param string $expression
- * @return array
- */
- protected function parseWhere($name, $expression)
- {
- return is_array($name) ? $name : [$name => $expression];
- }
- /**
- * Set a list of regular expression requirements on the route.
- *
- * @param array $wheres
- * @return $this
- */
- protected function whereArray(array $wheres)
- {
- foreach ($wheres as $name => $expression) {
- $this->where($name, $expression);
- }
- return $this;
- }
- /**
- * Add a prefix to the route URI.
- *
- * @param string $prefix
- * @return $this
- */
- public function prefix($prefix)
- {
- $uri = rtrim($prefix, '/').'/'.ltrim($this->uri, '/');
- $this->uri = trim($uri, '/');
- return $this;
- }
- /**
- * Get the URI associated with the route.
- *
- * @return string
- */
- public function getPath()
- {
- return $this->uri();
- }
- /**
- * Get the URI associated with the route.
- *
- * @return string
- */
- public function uri()
- {
- return $this->uri;
- }
- /**
- * Get the HTTP verbs the route responds to.
- *
- * @return array
- */
- public function getMethods()
- {
- return $this->methods();
- }
- /**
- * Get the HTTP verbs the route responds to.
- *
- * @return array
- */
- public function methods()
- {
- return $this->methods;
- }
- /**
- * Determine if the route only responds to HTTP requests.
- *
- * @return bool
- */
- public function httpOnly()
- {
- return in_array('http', $this->action, true);
- }
- /**
- * Determine if the route only responds to HTTPS requests.
- *
- * @return bool
- */
- public function httpsOnly()
- {
- return $this->secure();
- }
- /**
- * Determine if the route only responds to HTTPS requests.
- *
- * @return bool
- */
- public function secure()
- {
- return in_array('https', $this->action, true);
- }
- /**
- * Get the domain defined for the route.
- *
- * @return string|null
- */
- public function domain()
- {
- return isset($this->action['domain']) ? $this->action['domain'] : null;
- }
- /**
- * Get the URI that the route responds to.
- *
- * @return string
- */
- public function getUri()
- {
- return $this->uri;
- }
- /**
- * Set the URI that the route responds to.
- *
- * @param string $uri
- * @return $this
- */
- public function setUri($uri)
- {
- $this->uri = $uri;
- return $this;
- }
- /**
- * Get the prefix of the route instance.
- *
- * @return string
- */
- public function getPrefix()
- {
- return isset($this->action['prefix']) ? $this->action['prefix'] : null;
- }
- /**
- * Get the name of the route instance.
- *
- * @return string
- */
- public function getName()
- {
- return isset($this->action['as']) ? $this->action['as'] : null;
- }
- /**
- * Add or change the route name.
- *
- * @param string $name
- * @return $this
- */
- public function name($name)
- {
- $this->action['as'] = isset($this->action['as']) ? $this->action['as'].$name : $name;
- return $this;
- }
- /**
- * Set the handler for the route.
- *
- * @param \Closure|string $action
- * @return $this
- */
- public function uses($action)
- {
- $action = is_string($action) ? $this->addGroupNamespaceToStringUses($action) : $action;
- return $this->setAction(array_merge($this->action, $this->parseAction([
- 'uses' => $action,
- 'controller' => $action,
- ])));
- }
- /**
- * Parse a string based action for the "uses" fluent method.
- *
- * @param string $action
- * @return string
- */
- protected function addGroupNamespaceToStringUses($action)
- {
- $groupStack = last($this->router->getGroupStack());
- if (isset($groupStack['namespace']) && strpos($action, '\\') !== 0) {
- return $groupStack['namespace'].'\\'.$action;
- }
- return $action;
- }
- /**
- * Get the action name for the route.
- *
- * @return string
- */
- public function getActionName()
- {
- return isset($this->action['controller']) ? $this->action['controller'] : 'Closure';
- }
- /**
- * Get the action array for the route.
- *
- * @return array
- */
- public function getAction()
- {
- return $this->action;
- }
- /**
- * Set the action array for the route.
- *
- * @param array $action
- * @return $this
- */
- public function setAction(array $action)
- {
- $this->action = $action;
- return $this;
- }
- /**
- * Get the compiled version of the route.
- *
- * @return \Symfony\Component\Routing\CompiledRoute
- */
- public function getCompiled()
- {
- return $this->compiled;
- }
- /**
- * Set the router instance on the route.
- *
- * @param \Illuminate\Routing\Router $router
- * @return $this
- */
- public function setRouter(Router $router)
- {
- $this->router = $router;
- return $this;
- }
- /**
- * Set the container instance on the route.
- *
- * @param \Illuminate\Container\Container $container
- * @return $this
- */
- public function setContainer(Container $container)
- {
- $this->container = $container;
- return $this;
- }
- /**
- * Prepare the route instance for serialization.
- *
- * @return void
- *
- * @throws \LogicException
- */
- public function prepareForSerialization()
- {
- if ($this->action['uses'] instanceof Closure) {
- throw new LogicException("Unable to prepare route [{$this->uri}] for serialization. Uses Closure.");
- }
- unset($this->router, $this->container, $this->compiled);
- }
- /**
- * Dynamically access route parameters.
- *
- * @param string $key
- * @return mixed
- */
- public function __get($key)
- {
- return $this->parameter($key);
- }
- }