The path info always starts with a /.
Suppose this request is instantiated from /mysite on localhost:
* http://localhost/mysite returns an empty string
* http://localhost/mysite/about returns '/about'
* http://localhost/mysite/enco%20ded returns '/enco%20ded'
* http://localhost/mysite/about?var=1 returns '/about'
public getPathInfo ( ) : string | ||
return | string | The raw path (i.e. not urldecoded) |
/** * Handles a Request to convert it to a Response. * * When $catch is true, the implementation must catch all exceptions * and do its best to convert them to a Response instance. * * @param Request $request A Request instance * @param int $type The type of the request * (one of HttpKernelInterface::MASTER_REQUEST or HttpKernelInterface::SUB_REQUEST) * @param bool $catch Whether to catch exceptions or not * * @return Response A Response instance * * @throws \Exception When an Exception occurs during processing */ public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true) { try { $match = $this->routeMatch; if (!$match) { $match = $this->router->match($request->getPathInfo()); } if ($match) { list($module, $controller, $action) = $this->processRoute($match); $request->attributes->add(['_module' => $module, '_controller' => $controller, '_action' => $action]); $response = $this->dispatcher->dispatch($match['target'], $match['params']); } else { $response = $this->dispatcher->dispatch('Home#error', ['message' => 'Halaman tidak ditemukan: ' . $request->getPathInfo()]); $response->setStatusCode(Response::HTTP_NOT_FOUND); } } catch (HttpException $e) { if (!$catch) { throw $e; } $response = $this->dispatcher->dispatch('Home#error', ['message' => '[' . $e->getCode() . '] ' . $e->getMessage()]); $response->setStatusCode($e->getStatusCode()); } catch (Exception $e) { if (!$catch) { throw $e; } $response = $this->dispatcher->dispatch('Home#error', ['message' => '[' . $e->getCode() . '] ' . $e->getMessage()]); $response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR); } //$response->setMaxAge(300); return $response; }
/** * @param CanonicalUrlEvent $event */ public function generateUrlCanonical(CanonicalUrlEvent $event) { if ($event->getUrl() !== null) { return; } $parseUrlByCurrentLocale = $this->getParsedUrlByCurrentLocale(); if (empty($parseUrlByCurrentLocale['host'])) { return; } // Be sure to use the proper domain name $canonicalUrl = $parseUrlByCurrentLocale['scheme'] . '://' . $parseUrlByCurrentLocale['host']; // preserving a potential subdirectory, e.g. http://somehost.com/mydir/index.php/... $canonicalUrl .= $this->request->getBaseUrl(); // Remove script name from path, e.g. http://somehost.com/index.php/... $canonicalUrl = preg_replace("!/index(_dev)?\\.php!", '', $canonicalUrl); $path = $this->request->getPathInfo(); if (!empty($path) && $path != "/") { $canonicalUrl .= $path; $canonicalUrl = rtrim($canonicalUrl, '/'); } else { $queryString = $this->request->getQueryString(); if (!empty($queryString)) { $canonicalUrl .= '/?' . $queryString; } } $event->setUrl($canonicalUrl); }
public function matches(Request $request) { if (!$this->language) { throw new \LogicException('Unable to match the request as the expression language is not available.'); } return $this->language->evaluate($this->expression, array('request' => $request, 'method' => $request->getMethod(), 'path' => rawurldecode($request->getPathInfo()), 'host' => $request->getHost(), 'ip' => $request->getClientIp(), 'attributes' => $request->attributes->all())) && parent::matches($request); }
protected function initializeRequestAttributes(Request $request, $master) { if ($master) { // set the context even if the parsing does not need to be done // to have correct link generation $this->router->setContext(array('base_url' => $request->getBaseUrl(), 'method' => $request->getMethod(), 'host' => $request->getHost(), 'port' => $request->getPort(), 'is_secure' => $request->isSecure())); } if ($request->attributes->has('_controller')) { // routing is already done return; } // add attributes based on the path info (routing) try { $parameters = $this->router->match($request->getPathInfo()); if (null !== $this->logger) { $this->logger->info(sprintf('Matched route "%s" (parameters: %s)', $parameters['_route'], json_encode($parameters))); } $request->attributes->add($parameters); if ($locale = $request->attributes->get('_locale')) { $request->getSession()->setLocale($locale); } } catch (NotFoundException $e) { $message = sprintf('No route found for "%s %s"', $request->getMethod(), $request->getPathInfo()); if (null !== $this->logger) { $this->logger->err($message); } throw new NotFoundHttpException($message, $e); } catch (MethodNotAllowedException $e) { $message = sprintf('No route found for "%s %s": Method Not Allowed (Allow: %s)', $request->getMethod(), $request->getPathInfo(), strtoupper(implode(', ', $e->getAllowedMethods()))); if (null !== $this->logger) { $this->logger->err($message); } throw new MethodNotAllowedHttpException($e->getAllowedMethods(), $message, $e); } }
public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true) { $match = $this->router->match($request->getPathInfo()); $route = substr($request->getPathInfo(), strlen(rtrim($this->config['baseDir'], '/'))); if ($match) { $tokenValid = false; $jwtCookie = $this->config['jwt']['cookieName']; $jwtKey = $this->config['jwt']['key']; // check token from cookie if ($request->cookies->has($jwtCookie)) { $jwt = $request->cookies->get($jwtCookie); try { $decoded = JWT::decode($jwt, $jwtKey, ['HS256']); if ($decoded->e > time()) { $tokenValid = true; $this->auth->init($decoded->uid); } } catch (\Exception $e) { $tokenValid = false; if (!$catch) { throw $e; } $response = $this->dispatcher->dispatch('Home#error', ['message' => '[' . $e->getCode() . '] ' . $e->getMessage() . '<pre>' . $e->getTraceAsString() . '</pre>']); $response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR); return $response; } } $allowed = false; $isPublic = false; foreach ($this->config['publicArea'] as $publicRoute) { if (preg_match('/^' . addcslashes($publicRoute, '/') . '/', $route)) { $isPublic = true; break; } } if ($match['name'] == 'home') { $isPublic = true; } if ($isPublic) { if ($route == '/login' && $tokenValid) { return new RedirectResponse($this->router->generate('dashboard')); } $allowed = true; } else { $allowed = $tokenValid; } if ($allowed) { $this->app->setRouteMatch($match); return $this->app->handle($request, $type, $catch); } else { $this->flash->warning('Sesi Anda telah habis atau Anda tidak berhak mengakses halaman ini, silakan login terlebih dahulu!'); $response = $this->dispatcher->dispatch('User#login', []); $response->setStatusCode(Response::HTTP_UNAUTHORIZED); return $response; } } $response = $this->dispatcher->dispatch('Home#error', ['message' => 'Halaman tidak ditemukan: ' . $route]); $response->setStatusCode(Response::HTTP_NOT_FOUND); return $response; }
/** * {@inheritdoc} * * This method looks for a '_controller' request attribute that represents * the controller name (a string like ClassName::MethodName). */ public function getController(Request $request) { if (!($controller = $request->attributes->get('_controller'))) { if (null !== $this->logger) { $this->logger->warning('Unable to look for the controller as the "_controller" parameter is missing.'); } return false; } if (is_array($controller)) { return $controller; } if (is_object($controller)) { if (method_exists($controller, '__invoke')) { return $controller; } throw new \InvalidArgumentException(sprintf('Controller "%s" for URI "%s" is not callable.', get_class($controller), $request->getPathInfo())); } if (false === strpos($controller, ':')) { if (method_exists($controller, '__invoke')) { return $this->instantiateController($controller); } elseif (function_exists($controller)) { return $controller; } } $callable = $this->createController($controller); if (!is_callable($callable)) { throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable. %s', $request->getPathInfo(), $this->getControllerError($callable))); } return $callable; }
/** * {@inheritdoc} * * This method looks for a '_controller' request attribute that represents * the controller name (a string like ClassName::MethodName). * * @api */ public function getController(Request $request) { $controller = $request->attributes->get('controller'); if ($request->attributes->has('_sub_request') && $request->attributes->get('_sub_request')) { $controller = $request->attributes->get('_controller'); } if (!$controller) { if (null !== $this->logger) { $this->logger->warning('Unable to look for the controller as the "_controller" parameter is missing'); } return false; } if (is_array($controller)) { return $controller; } if (is_object($controller)) { if (method_exists($controller, '__invoke')) { return $controller; } throw new \InvalidArgumentException(sprintf('Controller "%s" for URI "%s" is not callable.', get_class($controller), $request->getPathInfo())); } $prepare = $this->prepare($request->attributes->all()); $request->attributes->set('_bundle', $prepare['bundle']); $request->attributes->set('_controller', strtolower($prepare['parts'][1])); $request->attributes->set('_action', strtolower($prepare['parts'][2])); $callable = array($this->instantiateController($prepare['controller']), $prepare['action']); $request->attributes->set('_callable', $callable); if (!is_callable($callable)) { throw new \InvalidArgumentException(sprintf('Controller "%s" for URI "%s" is not callable.', $controller, $request->getPathInfo())); } return $callable; }
/** * This method looks for a '_controller' request attribute that represents * the controller name (a string like ClassName::MethodName). * * @param Symfony\Component\HttpFoundation\Request $request The request we are handeling. * @throws InvalidArgumentException If the controller is not callable. * @return Symfony\Bundle\FrameworkBundle\Controller\Controller The controller. */ public function getController(Request $request) { if (!($controller = $request->attributes->get('_controller'))) { return false; } if (is_array($controller)) { return $controller; } if (is_object($controller)) { if (method_exists($controller, '__invoke')) { return $controller; } throw new \InvalidArgumentException(sprintf('Controller "%s" for URI "%s" is not callable.', get_class($controller), $request->getPathInfo())); } if (false === strpos($controller, ':')) { if (method_exists($controller, '__invoke')) { return $this->instantiateController($controller); } elseif (function_exists($controller)) { return $controller; } } $callable = $this->createController($controller); if (!is_callable($callable)) { throw new \InvalidArgumentException(sprintf('Controller "%s" for URI "%s" is not callable.', $controller, $request->getPathInfo())); } return $callable; }
public function getController(Request $request) { $controller = $request->attributes->get('_controller'); if (!$controller) { throw new \Exception(sprintf('No _controller attribute set on Request with URI %s', $request->getPathInfo())); } $method = $request->attributes->get('_method'); if (!$method) { throw new \Exception(sprintf('No _method attribute set on Request with URI %s', $request->getPathInfo())); } $method .= 'Action'; //check if controller is defined as a service (it begins with //'::') $prefix = '::'; if (substr($controller, 0, 2) === $prefix) { $service = substr($controller, 2); if (!$this->neptune->offsetExists($service)) { throw new \Exception(sprintf('Undefined controller service %s', $service)); } $controller = $this->configureController($this->neptune[$service]); return array($controller, $method); } //if $controller begins with a backslash, assume a class name if (substr($controller, 0, 1) === '\\') { $class = $controller; } else { $class = $this->getControllerClass($controller); } if (!class_exists($class)) { throw new \Exception(sprintf('Controller not found: %s', $class)); } $controller = $this->configureController(new $class()); return array($controller, $method); }
/** * Gets list of candidate Route objects for request * * @return array List of Route objects */ public function getCandidates() { $candidates = array(); foreach ($this->collection->all() as $name => $route) { $specs = array(); preg_match_all('/\\{\\w+\\}/', $route->getPath(), $matches); if (isset($matches[0])) { $specs = $matches[0]; } foreach ($specs as $spec) { $param = substr($spec, 1, -1); $regexSpec = '\\' . $spec . '\\'; $requirements = $route->getRequirements(); if (isset($requirements[$param])) { $route->setRegex(str_replace($spec, $this->getRegexOperand($requirements[$param]), $route->getRegex())); } } // Build regeular expression to match routes $route->setRegex('^' . '/' . ltrim(trim($route->getRegex()), '/') . '/?$'); $route->setRegex('/' . str_replace('/', '\\/', $route->getRegex()) . '/'); if (preg_match($route->getRegex(), $this->request->getPathInfo())) { // We have a match $candidates[] = $route; } } return $candidates; }
/** * @throws \Exception * @return array: */ public function getControllerMethod($uri = null) { try { $result = false; $givenRoute = $uri == null ? $this->request->getPathInfo() : $uri; foreach ($this->routesCollection as $route) { if (!$result && $route['pattern'] == $givenRoute) { $controller = $route['controller']; $class = explode('::', $controller)[0]; $method = explode('::', $controller)[1]; if (!class_exists($class)) { throw new \Exception('The route class doesn\'t exist!'); } else { if (!method_exists($class, $method)) { throw new \Exception('The route class\'s method doesn\'t exist!'); } } $this->logger->addInfo("Route controller method found: {$class} -> {$method}"); $result = array('class' => $class, 'method' => $method); } } if (!$result) { throw new \Exception('Route not found'); } else { return $result; } } catch (\Exception $e) { $this->logger->addError('Error handling route: ' . $e->getMessage()); throw new \Exception($e->getMessage(), $e->getCode(), $e->getPrevious()); } }
/** * @return array|bool */ protected function resolveController() { try { // doctrine mabo jambo to prepare route detection $context = new RequestContext(); $context->fromRequest($this->request); $matcher = new UrlMatcher($this->routeCollection, $context); // try detecting controller & stuff $this->request->attributes->add($matcher->match($this->request->getPathInfo())); // resolve controller $resolver = new ControllerResolver(); $controller = $resolver->getController($this->request); $controller = $this->assembleController($controller); // adding request and response variables to the controller if (!empty($controller[0]) && $controller[0] instanceof AbstractSimplexController) { $controller[0]->setRequest($this->request)->setResponse($this->response); } else { // or as attributes for a 'function' controller $req = array('request' => $this->request, 'response' => $this->response); $this->request->attributes->add($req); } // parsing arguments for the request and adding a last argument the request parameter itself $arguments = $resolver->getArguments($this->request, $controller); return array($controller, $arguments); } catch (ResourceNotFoundException $e) { } return false; }
/** * Base fallback action. * Will be basically used for every legacy module. * * @return \eZ\Bundle\EzPublishLegacyBundle\LegacyResponse */ public function indexAction() { $kernelClosure = $this->kernelClosure; /** @var \eZ\Publish\Core\MVC\Legacy\Kernel $kernel */ $kernel = $kernelClosure(); $legacyMode = $this->configResolver->getParameter('legacy_mode'); //Empêche le front d'aller dans de l'eZ legacy if (!$legacyMode && substr($this->request->getPathInfo(), 0, 18) != '/content/download/') { throw new NotFoundHttpException('Adresse non trouvée'); } $kernel->setUseExceptions(false); // Fix up legacy URI with current request since we can be in a sub-request here. $this->uriHelper->updateLegacyURI($this->request); // If we have a layout for legacy AND we're not in legacy mode, we ask the legacy kernel not to generate layout. if (isset($this->legacyLayout) && !$legacyMode) { $kernel->setUsePagelayout(false); } $result = $kernel->run(); $kernel->setUseExceptions(true); if ($result instanceof ezpKernelRedirect) { return $this->legacyResponseManager->generateRedirectResponse($result); } $this->legacyHelper->loadDataFromModuleResult($result->getAttribute('module_result')); $response = $this->legacyResponseManager->generateResponseFromModuleResult($result); $this->legacyResponseManager->mapHeaders(headers_list(), $response); return $response; }
public function onRequest(Request $request) { $session = $request->getSession(); list($id, $role) = $session->get('user', array(null, 'ROLE_ANONYMOUS')); if (null === $id && $request->cookies->has(Remember::REMEMBER_ME)) { if ($this->remember->check($request->cookies->get(Remember::REMEMBER_ME))) { list($id, $role) = $this->remember->getIt(); $session->set('user', array($id, $role)); } } $this->provider->setRole($role); if (!$this->provider->isAllowed($request->getPathInfo())) { throw new Exception\AccessDeniedException("Access denied to " . $request->getPathInfo()); } if (null !== $id) { // Ban check $clientIp = $request->getClientIp(); $ban = Ban::findActive($id, $clientIp); if (!empty($ban)) { throw new BannedException($ban[0], Response::HTTP_FORBIDDEN); } // User loading. $user = User::find($id); if (null !== $user) { $user->ip = $clientIp; $user->save(); $this->provider->setUser($user); $this->provider->setAuthenticated(true); } } }
public function isNodeActive(NavigationNode $node) { if ($this->request === null) { $this->request = $this->container->get('request'); } $path = $this->request->getPathInfo(); return $path === $node->getLink(); }
/** * Performs route matching & dispatch and sends the response. * * @return $this */ public function run() { // Route $match = $this->router->match($this->request->getPathInfo(), $this->request->getMethod(), $this->request->getHttpHost(false)); // Dispatch $this->dispatch($match); // Respond $this->response->send(); }
/** * @param Request $request * @return \Symfony\Component\HttpFoundation\RedirectResponse|void */ public function checkUserRole(Request $request) { if ($request->getPathInfo() === '/login' && $this->app['session']->has('username')) { return $this->app->redirect($this->app["url_generator"]->generate("beranda")); } if (!$this->app['session']->has('username') && !($request->getPathInfo() === '/login')) { return $this->app->redirect($this->app["url_generator"]->generate("login")); } }
/** * @return string */ private function getPathWithQueryString() { $path = $this->message->getPathInfo(); $qs = $this->message->getQueryString(); if ($qs === null) { return $path; } else { return "{$path}?{$qs}"; } }
/** * {@inheritdoc} */ public function collect(Request $request, Response $response, \Exception $exception = null) { $this->data['path_info'] = $request->getPathInfo(); if (!$this->router) { $this->data['traces'] = array(); } else { $matcher = new TraceableUrlMatcher($this->router->getRouteCollection(), $this->router->getContext()); $this->data['traces'] = $matcher->getTraces($request->getPathInfo()); } }
/** * (non-PHPdoc) * @see Spewia\Router.RouterInterface::parseRequest() */ public function parseRequest(Request $request) { //check if any of the entries in the patterns is the same that the uri passed in the Request $identifier = $this->getIdentifierByUri($request->getPathInfo()); if ($identifier === NULL) { throw new RouteNotFoundException(); } $params = $this->getParamsFromRequestUri($identifier, $request->getPathInfo()); $this->routing_configuration[$identifier]['params'] = $params; return $this->routing_configuration[$identifier]; }
/** * Run the application and match routes to the requested uri * * @param $routes * @return App * @throws Exceptions\MethodNotAllowed * @throws Exceptions\NotFound */ public function run(array $routes) : App { array_walk($routes, function (array $route) { $this->router->routeRequestCollection[] = new RouteRequest($route['httpMethod'], $route['route'], $route['handler']); }); $this->router->dispatch($this->request->getPathInfo(), $this->request->getMethod(), function ($handler, array $args = []) { $response = call_user_func_array($handler, [$this->request, $args]); $response->send(); }); return $this; }
/** * {@inheritdoc} */ public function getController(Request $request) { if (!($controller = $request->attributes->get('_controller'))) { throw new \LogicException(sprintf('Controller for URI "%s" could not be found because the "_controller" parameter is missing.', $request->getPathInfo())); } try { return $this->callableResolver->resolve($controller); } catch (NotCallableException $e) { throw new \InvalidArgumentException(sprintf('Controller for URI "%s" is not callable: %s', $request->getPathInfo(), $e->getMessage())); } }
/** * Checks that a given path matches the Request. * * @param Request $request A Request instance * @param string $path A path (an absolute path (/foo), an absolute URL (http://...), or a route name (foo)) * * @return Boolean true if the path is the same as the one from the Request, false otherwise */ public function checkRequestPath(Request $request, $path) { if ('/' !== $path[0]) { try { $parameters = $this->router->match($request->getPathInfo()); return $path === $parameters['_route']; } catch (\Exception $e) { return false; } } return $path === $request->getPathInfo(); }
public function buildFragmentListener(UriSigner $uriSigner, $fragmentPath, $fragmentListenerClass) { // Ensure that current pathinfo ends with configured fragment path. // If so, consider it as the fragment path. // This ensures to have URI siteaccess compatible fragment paths. $pathInfo = $this->request->getPathInfo(); if (substr($pathInfo, -strlen($fragmentPath)) === $fragmentPath) { $fragmentPath = $pathInfo; } $fragmentListener = new $fragmentListenerClass($uriSigner, $fragmentPath); return $fragmentListener; }
/** * On kernel response event * * @param FilterResponseEvent $event */ public function onKernelResponse(FilterResponseEvent $event) { // Only master request and 200 OK are processed if (HttpKernelInterface::MASTER_REQUEST === $event->getRequestType() && $event->getResponse()->isOk()) { $route = $this->router->match($this->request->getPathInfo()); // Ignore internal route if (0 === stripos($route['_route'], '_')) { return; } $this->session->set('_unifik.last_master_request_uri', $this->request->getUri()); $this->session->set('_unifik.last_master_request_route', $route); } }
/** * @param Request $request * @param bool $sendResponse * @return Response */ public function handleHttpRequest(Request $request = null, $sendResponse = true) : Response { try { $this->getDIContainer()->provide('request', $request); $this->initRuntime($request); $route = $this->getRouter()->route($this->request); if ($route->isNotFound() === false) { $this->onRoute($route); return $this->sendResponse($this->runController($route), $sendResponse); } throw new HttpNotFoundException(sprintf('Unable to match route for: %s', $this->request->getMethod() . ' ' . $this->request->getPathInfo())); } catch (\Exception $e) { return $this->handleError($e, $sendResponse); } }
/** * {@inheritdoc} */ public function matchItem(ItemInterface $item) { if (!$this->request) { return; } $content = $item->getExtra('content'); if ($content instanceof Route && $content->hasOption('currentUriPrefix')) { $currentUriPrefix = $content->getOption('currentUriPrefix'); $currentUriPrefix = str_replace('{_locale}', $this->request->getLocale(), $currentUriPrefix); if (0 === strncmp($this->request->getPathInfo(), $currentUriPrefix, strlen($currentUriPrefix))) { return true; } } return; }
/** * Parses the requested route to fetch * - the resource (databox, basket, record etc ..) * - general action (list, add, search) * - the action (setstatus, setname etc..) * - the aspect (collections, related, content etc..) * * @param ApiLog $log * @param Request $request * @param Response $response */ private function setDetails(ApiLog $log, Request $request, Response $response) { $chunks = explode('/', trim($request->getPathInfo(), '/')); if (false === $response->isOk() || sizeof($chunks) === 0) { return; } switch ($chunks[0]) { case ApiLog::DATABOXES_RESOURCE: $this->hydrateDataboxes($log, $chunks); break; case ApiLog::RECORDS_RESOURCE: $this->hydrateRecords($log, $chunks); break; case ApiLog::BASKETS_RESOURCE: $this->hydrateBaskets($log, $chunks); break; case ApiLog::FEEDS_RESOURCE: $this->hydrateFeeds($log, $chunks); break; case ApiLog::QUARANTINE_RESOURCE: $this->hydrateQuarantine($log, $chunks); break; case ApiLog::STORIES_RESOURCE: $this->hydrateStories($log, $chunks); break; case ApiLog::MONITOR_RESOURCE: $this->hydrateMonitor($log, $chunks); break; } }
/** * {@inheritDoc} * * This will return any document found at the url or up the path to the * prefix. If any of the documents does not extend the symfony Route * object, it is filtered out. In the extreme case this can also lead to an * empty list being returned. */ public function getRouteCollectionForRequest(Request $request) { $url = $request->getPathInfo(); $candidates = $this->getCandidates($url); $collection = new RouteCollection(); if (empty($candidates)) { return $collection; } try { $routes = $this->dm->findMany($this->className, $candidates); // filter for valid route objects // we can not search for a specific class as PHPCR does not know class inheritance // but optionally we could define a node type foreach ($routes as $key => $route) { if ($route instanceof SymfonyRoute) { if (preg_match('/.+\\.([a-z]+)$/i', $url, $matches)) { if ($route->getDefault('_format') === $matches[1]) { continue; } $route->setDefault('_format', $matches[1]); } // SYMFONY 2.1 COMPATIBILITY: tweak route name $key = trim(preg_replace('/[^a-z0-9A-Z_.]/', '_', $key), '_'); $collection->add($key, $route); } } } catch (RepositoryException $e) { // TODO: how to determine whether this is a relevant exception or not? // for example, getting /my//test (note the double /) is just an invalid path // and means another router might handle this. // but if the PHPCR backend is down for example, we want to alert the user } return $collection; }
/** * @param Request $request * @return \Symfony\Component\HttpFoundation\RedirectResponse */ public function removeTrailingSlashAction(Request $request) { $pathInfo = $request->getPathInfo(); $requestUri = $request->getRequestUri(); $url = str_replace($pathInfo, rtrim($pathInfo, ' /'), $requestUri); return $this->redirect($url, 301); }