Merge the group stack with the controller action.

@param  \Nova\Routing\Route  $route
@return void
357040
protected function mergeGroupAttributesIntoRoute($route)
    {
        $action = $this->mergeWithLastGroup($route->getAction());

        $route->setAction($action);
    }
632130
public function add(Route $route, array $params = [])
    {
        $callback = $route->getCallable();
        if (empty($callback)) {
            return;
        }

        $this->routes[] = $route->getRoute();
        $paramNames = $route->getParamNames();
        foreach ($paramNames as $name) {
            if (isset($params[$name])) {
                $this->setParam($name, $params[$name]);
            }
        }

        if (is_array($callback)) {
            $this->callable = array_merge($this->callable, $callback);
        } elseif (!in_array($callback, $this->callable)) {
            $this->callable[] = $callback;
        }
    }
550863
public function appendRoute(Route $route)
    {
        if (!$originalRoute = optional($this->routes)[$route->slug()]) {
            return "Route {$route->slug()} not found";
        }

        return $this->routes[$route->slug()]['groups'] =
            $originalRoute['groups']->merge($route->get()['groups']);
    }
1308670
public function execute(Routes $routes): void
	{
		$routeCollection = [];

		// Build table rows

		foreach($routes->getRoutes() as $route)
		{
			// Normalize action name

			$action = ($route->getAction() instanceof Closure) ? 'Closure' : $route->getAction();

			// Build table row

			$routeCollection[] =
			[
				$route->getRoute(),
				implode(', ', $route->getMethods()),
				$action,
				implode(', ', $route->getMiddleware()),
				implode(', ', $route->getConstraints()),
				(string) $route->getName(),
			];
		}

		// Draw table

		$headers =
		[
			'<green>Route</green>',
			'<green>Allowed methods</green>',
			'<green>Action</green>',
			'<green>Middleware *</green>',
			'<green>Constraints **</green>',
			'<green>Name</green>',
		];

		$this->table($headers, $routeCollection);

		$this->write('<green>*</green> <faded>Global middleware is not listed.</faded>');
		$this->write('<green>**</green> <faded>Global constraints are not listed.</faded>');
	}
482432
public function addRoute(Route $route) {
        if (!in_array($route, $this->routes)) {
            $this->routes[] = $route;
        }
    }
837391
public function remove(Route $route)
    {
        $id = array_search($route, $this->routes);
        if ($id === false) {
            throw new \UnderflowException('Given Route not found');
        }

        unset($this->routes[$id]);
    }
500812
function update($route) {
        $route->pattern = $this->parser->trimPath($route->pattern);
        return parent::update($route);
    }
1224178
public function addRoute($actionName, Route $route)
    {
        !array_key_exists($actionName, $this->routes) or \PhpBoot\abort("repeated @route for {$this->className}::$actionName");
        $this->routes[$actionName] = $route;
    }
799988
protected function appendGroupInfo(Route $route): void
    {
        $path = $bak = $route->getPath();

        // Always add '/' prefix.
        $path = \strpos($path, '/') === 0 ? $path : '/' . $path;
        $path = $this->currentGroupPrefix . $path;

        // Has setting 'ignoreLastSlash'
        if ($path !== '/' && $this->ignoreLastSlash) {
            $path = \rtrim($path, '/');
        }

        // Not in group and path not change.
        if ($bak === $path) {
            return;
        }

        $route->setPath($path);

        // Not in group
        if (!$this->currentGroupPrefix) {
            return;
        }

        if ($this->currentGroupOption) {
            $route->setOptions(\array_merge($this->currentGroupOption, $route->getOptions()));
        }

        // Prepend group middleware at before.
        if ($this->currentGroupChains) {
            $route->setChains(\array_merge($this->currentGroupChains, $route->getChains()));
        }
    }
1209587
protected function routerMatchedHandler(Route $route)
    {
        if ($route->getName()) {
            // someaction (route name/alias)
            $routeName = $route->getName();
        } elseif ($route->getActionName()) {
            // SomeController@someAction (controller action)
            $routeName = $route->getActionName();
        }
        if (empty($routeName) || $routeName === 'Closure') {
            // /someaction // Fallback to the url
            $routeName = $route->uri();
        }

        Integration::addBreadcrumb(new Breadcrumb(
            Breadcrumb::LEVEL_INFO,
            Breadcrumb::TYPE_NAVIGATION,
            'route',
            $routeName
        ));
        Integration::setTransaction($routeName);
    }
550633
protected function addToCollections($route)
    {
        $fullUri = $route->getDomain() . $route->getUri();

        $method = null;
        foreach ($route->getMethods() as $method) {
            $this->routes[$method][$fullUri] = $route;
        }

        $this->allRoutes[$method . $fullUri] = $route;
    }
1297815
private function loadAndParseRoute($route)
    {
         // Get meta into view structure
         $meta = $this->getMetaForRoute($route);
         unset($meta["__toc__"]);
         unset($meta["views"]);

        // Get filtered content from route
        list($routeIndex, , $filtered) =
            $this->mapRoute2Content($route);

        // Merge frontmatter with meta
        // then merge frontmatter base into views main
        $filtered->frontmatter = array_merge_recursive_distinct(
            $meta,
            $filtered->frontmatter
        );

        // Do phase 2 processing to get new filtered content
        // (and updated frontmatter)
        $this->processContentPhaseTwo($filtered);

        // Create complete frontmatter, inluding content
        $filtered->frontmatter["data"]["content"] = isset($filtered->text)
            ? $filtered->text
            : null;

        // Load additional content for view, based on data-meta
        $view = ["main" => $filtered->frontmatter];
        $this->loadAdditionalContent($view, $route, $routeIndex);

        return $view["main"];
    }
832688
private function dispatch($request, $route)
    {
        if ($route->matched()) {
            $request = $request->withPathToMatch($route->matched(), $route->trailing());
        }
        // dispatch the route!
        return $this->dispatcher->withRoute($route)->__invoke($request);
    }
32757
public function group(array $attributes, $routes)
    {
        $this->updateGroupStack($attributes);

        // Once we have updated the group stack, we'll load the provided routes and
        // merge in the group's attributes when the routes are created. After we
        // have created the routes, we will pop the attributes off the stack.
        $this->loadRoutes($routes);

        array_pop($this->groupStack);
    }
492445
protected function processRoute($route)
	{
		$routeAction = $route->getAction();

		$this->getParentCommand()->info('Processing route [' . implode('/', $route->methods()) . '] ' . $routeAction['uri']);

		$routeControllerDocBlock = $this->getRouteControllerDocBlock($route);
		$routeControllerOperationTags = $this->getDocBlockOperationTags($routeControllerDocBlock);

		foreach ($route->methods() as $httpMethod) {
			// Ignore HEAD

			if (strtolower($httpMethod) == 'head') {
				continue;
			}

			if (isset($this->openAPI->paths[$routeAction['uri']])) {
				$pathItem = $this->openAPI->paths[$routeAction['uri']];
			} else {
				$pathItem = $this->openAPI->paths[$routeAction['uri']] = new PathItem();

				if (!is_null($routeControllerDocBlock)) {
					$pathItem->summary = $routeControllerDocBlock->getSummary();
					if (empty($pathItem->summary)) {
						$pathItem->summary = null;
					}
					$routeControllerDescriptionDocBlock = $routeControllerDocBlock->getDescription();
					$pathItem->description = $routeControllerDescriptionDocBlock->render();
					if (empty($pathItem->description)) {
						$pathItem->description = null;
					}
				}
			}

			$operation = new Operation();

			$operationTags = $routeControllerOperationTags;

			$routeMethodDocBlock = $this->getRouteMethodDocBlock($route);
			$extraParameterRefTags = [];

			if (!is_null($routeMethodDocBlock)) {
				$operation->summary = $routeMethodDocBlock->getSummary();
				if (empty($operation->summary)) {
					$operation->summary = null;
				}
				$routeMethodDescriptionDocBlock = $routeMethodDocBlock->getDescription();
				$operation->description = $routeMethodDescriptionDocBlock->render();
				if (empty($operation->description)) {
					$operation->description = null;
				}
				$routeMethodOperationTags = $this->getDocBlockOperationTags($routeMethodDocBlock);

				$operationTags = array_merge($routeControllerOperationTags, $routeMethodOperationTags);
				$extraParameterRefTags = $this->getDocBlockExtraParameterRefTags($routeMethodDocBlock);

				$operation->operationId = $this->getDocBlockOperationId($routeMethodDocBlock);
			}

			if (is_null($operation->operationId)) {
				switch (strtolower($httpMethod)) {
					case 'patch':
					case 'put':
						$operation->operationId = strtolower($httpMethod) . ucfirst(array_last(explode('.', $routeAction['as'])));
						break;
					default :
						$operation->operationId = array_last(explode('.', $routeAction['as']));
				}
			}

			if (count($operationTags) > 0) {
				$operation->tags = $operationTags;
			}

			// Try
			$routePathParameters = $this->getRoutePathParameters($route);

			foreach ($routePathParameters as $parameterName => $parameterData) {
				$parameterDescription = isset($parameterData['docDescription']) ? $parameterData['docDescription'] : '';
				if (trim($parameterDescription) == '') {
					$parameterDescription = null;
				}
				$parameter = new Parameter([
					'name' => $parameterName,
					'in' => 'path',
					'description' => $parameterDescription,
					'required' => true,
				]);
				if (isset($parameterData['type'])) {
					$parameter->schema = new Schema([
						'type' => $parameterData['type']
					]);
				}
				if (isset($parameterData['docType'])) {
					$parameter->schema = new Schema([
						'type' => $parameterData['docType']
					]);
				}
				$operation->parameters[] = $parameter;
			}

			// Try to get route validation rules
			$routeValidationRules = $this->getRouteValidationRules($route);

			if (count($routeValidationRules) > 0) {
				switch (strtolower($httpMethod)) {
					case 'get':
					//case 'head':

						foreach ($routeValidationRules as $parameterName => $rulesString) {
							$rules = explode('|', $rulesString);

							$parameter = new Parameter([
								'name' => $parameterName,
								'in' => 'query',
								'description' => null, /* @todo Grab description from phpdoc custom tag ? */
								'required' => in_array('required', $rules),
							]);

							$parameter->schema = $this->getPropertyValidationRulesSchema(
								$rules,
								'Validation rules for parameter "' . $parameterName . '"',
								true
							);
							
							if (is_null($parameter->schema->format)) {
								// ignore this parameter if no type found
								$this->getParentCommand()->warn('  Ignore parameter "' . $parameterName . '"');
								continue;
							}

							// Add if not already added from the "path" parameters
							$find = false;
							if (is_null($operation->parameters)) {
								$operation->parameters = [];
							}
							/** @var Parameter $p */
							foreach ($operation->parameters as $p) {
								if ($p->name == $parameter->name) {
									$find = true;
								}
							}
							if (!$find) {
								$operation->parameters[] = $parameter;
							}
						}

						break;

					case 'put':
					case 'patch':
					case 'post':

						$requestBody = new RequestBody();
						$mediaType = new MediaType();
						$mediaType->schema = new Schema();
						$mediaType->schema->properties = [];

						// Change to multi-part if file in parameters ("string" type and "binary" format)
						$contentType = 'application/json';
						
						foreach ($routeValidationRules as $parameterName => $rulesString) {
							$rules = explode('|', $rulesString);
							$schema = $this->getPropertyValidationRulesSchema(
								$rules,
								'Validation rules for parameter "' . $parameterName . '"',
								true
							);
							
							// ignore this property if no type found
							if (is_null($schema->type)) {
								$this->getParentCommand()->warn('  Ignore parameter "' . $parameterName . '"');
								continue;
							}
							
							// Change to multi-part if file in parameters ("string" type and "binary" format)
							if ($schema->type == 'string' && $schema->format == 'binary') {
								$contentType = 'multipart/form-data';
								// Change mediaType schema type
								$mediaType->schema->type = 'object';
							}
							
							$mediaType->schema->properties[$parameterName] = $schema;
						}

						$mediaType->schema->required = $this->getValidationRulesSchemaRequired($routeValidationRules);

						$requestBody->content[$contentType] = $mediaType;
						$operation->requestBody = $requestBody;

						$operation->responses = [];

						break;
				}
			}

			// Append extra parameter refs

			foreach ($extraParameterRefTags as $extraParameterRefTag) {
				$parameterRef = new Reference([
					'ref' => $extraParameterRefTag
				]);

				if (is_null($operation->parameters)) {
					$operation->parameters = [];
				}

				$operation->parameters[] = $parameterRef;
			}

			// First response

			$response = new Response();
			$responseMediaType = null;

			$apiResponseSchemaRefTags = $routeMethodDocBlock->getTagsByName('OpenApiResponseSchemaRef');
			if (count($apiResponseSchemaRefTags) > 0) {
				if (is_null($responseMediaType)) {
					$responseMediaType = new MediaType();
				}
				$apiResponseSchemaRefTag = $apiResponseSchemaRefTags[0];
				$apiResponseSchemaRef = trim(str_replace('@OpenApiResponseSchemaRef', '', $apiResponseSchemaRefTag->render()));
				$responseMediaType->schema = new Reference([
					'ref' => $apiResponseSchemaRef
				]);
			}
			
			$response->description = '';
			$apiResponseDescriptionTags = $routeMethodDocBlock->getTagsByName('OpenApiResponseDescription');
			if (count($apiResponseDescriptionTags) > 0) {
				$apiResponseDescriptionTag = $apiResponseDescriptionTags[0];
				$apiResponseDescription = trim(str_replace('@OpenApiResponseDescription', '', $apiResponseDescriptionTag->render()));
				$response->description = $apiResponseDescription;
			}

			$apiDocsNoCallTags = $routeMethodDocBlock->getTagsByName('ApiDocsNoCall');
			if (count($apiDocsNoCallTags) == 0) {
				$exampleResponse = $this->getRouteCallExampleResponse($route, $httpMethod);
				if (!is_null($exampleResponse)) {
					if (is_null($responseMediaType)) {
						$responseMediaType = new MediaType();
					}

					$exampleSchemaId = $this->getRouteExampleResponseId($route);

					// Create Example schema in components

					if (is_null($this->openAPI->components)) {
						$this->openAPI->components = new Components();
					}

					$this->openAPI->components->examples[$exampleSchemaId] = new Example([
						'value' => json_decode($exampleResponse, true)
					]);

					$responseMediaType->example = new Reference([
						'ref' => '#/components/examples/' . $exampleSchemaId
					]);
				}
			}

			if (!is_null($responseMediaType)) {
				$response->content['application/json'] = $responseMediaType;
			}
			
			// Excepted HTTP code specified ? "OpenApiResponseExceptedHTTPCode" tag
			
			$apiResponseExceptedHTTPCode = null;
			$apiResponseExceptedHTTPCodeTags = $routeMethodDocBlock->getTagsByName('OpenApiResponseExceptedHTTPCode');
			if (count($apiResponseExceptedHTTPCodeTags) > 0) {
				$apiResponseExceptedHTTPCodeTag = $apiResponseExceptedHTTPCodeTags[0];
				$apiResponseExceptedHTTPCode = trim(str_replace('@OpenApiResponseExceptedHTTPCode', '', $apiResponseExceptedHTTPCodeTag->render()));
			}

			if (!is_null($apiResponseExceptedHTTPCode)) {
				$operation->responses[$apiResponseExceptedHTTPCode] = $response;
			} else {
				switch (strtolower($httpMethod)) {
					case 'get':
						//case 'head':
						$operation->responses['200'] = $response;
						break;
					
					case 'put':
					case 'patch':
						$operation->responses['200'] = $response;
						break;
						
					case 'post':
						$operation->responses['201'] = $response;
						break;
					
					case 'delete':
						$operation->responses['204'] = $response;
						break;
				}
			}

			// Default response (Errors)

			$defaultResponse = new Response();
			$defaultResponseMediaType = null;

			$apiDefaultResponseSchemaRefTags = $routeMethodDocBlock->getTagsByName('OpenApiDefaultResponseSchemaRef');
			if (count($apiDefaultResponseSchemaRefTags) > 0) {
				if (is_null($defaultResponseMediaType)) {
					$defaultResponseMediaType = new MediaType();
				}
				$apiDefaultResponseSchemaRefTag = $apiDefaultResponseSchemaRefTags[0];
				$apiDefaultResponseSchemaRef = trim(str_replace('@OpenApiDefaultResponseSchemaRef', '', $apiDefaultResponseSchemaRefTag->render()));
				$defaultResponseMediaType->schema = new Reference([
					'ref' => $apiDefaultResponseSchemaRef
				]);
			}

			$defaultResponse->description = '';
			$apiDefaultResponseDescriptionTags = $routeMethodDocBlock->getTagsByName('OpenApiDefaultResponseDescription');
			if (count($apiDefaultResponseDescriptionTags) > 0) {
				$apiDefaultResponseDescriptionTag = $apiResponseDescriptionTags[0];
				$apiDefaultResponseDescription = trim(str_replace('@OpenApiDefaultResponseDescription', '', $apiDefaultResponseDescriptionTag->render()));
				$defaultResponse->description = $apiDefaultResponseDescription;
			}

			if (!is_null($defaultResponseMediaType)) {
				$defaultResponse->content['application/json'] = $defaultResponseMediaType;
			}

			$operation->responses['default'] = $defaultResponse;

			$pathItem->{strtolower($httpMethod)} = $operation;
		}
	}
125514
protected function addLookups($route)
    {
        // If the route has a name, we will add it to the name look-up table so that we
        // will quickly be able to find any route associate with a name and not have
        // to iterate through every route every time we need to perform a look-up.
        if ($name = $route->getName()) {
            $this->nameList[$name] = $route;
        }

        // When the route is routing to a controller we will also store the action that
        // is used by the route. This will let us reverse route to controllers while
        // processing a request and easily generate URLs to the given controllers.
        $action = $route->getAction();

        if (isset($action['controller'])) {
            $this->addToActionList($action, $route);
        }
    }
433470
public static function configureRoutes(GroupInterface $routes): void
    {
        $routes->group('', function (GroupInterface $routes): void {

            $routes->addContainerConfigurators([
                L10nContainerConfigurator::CONFIGURATOR,
            ]);

            for ($i = 0; $i < 10 + 10 * 5; ++$i) {
                $routes->post("/posts$i/create", [PostsController::class, PostsController::METHOD_CREATE]);
            }

        });
    }