3 namespace Drupal\Core\Path;
5 use Drupal\Component\Utility\UrlHelper;
6 use Drupal\Core\ParamConverter\ParamNotConvertedException;
7 use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
8 use Drupal\Core\Routing\AccessAwareRouterInterface;
9 use Drupal\Core\Routing\RequestContext;
10 use Drupal\Core\Session\AccountInterface;
12 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
13 use Symfony\Component\HttpFoundation\Request;
14 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
15 use Symfony\Component\Routing\Exception\MethodNotAllowedException;
16 use Symfony\Component\Routing\Exception\ResourceNotFoundException;
17 use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
20 * Provides a default path validator and access checker.
22 class PathValidator implements PathValidatorInterface {
25 * The access aware router.
27 * @var \Drupal\Core\Routing\AccessAwareRouterInterface
29 protected $accessAwareRouter;
32 * A router implementation which does not check access.
34 * @var \Symfony\Component\Routing\Matcher\UrlMatcherInterface
36 protected $accessUnawareRouter;
41 * @var \Drupal\Core\Session\AccountInterface
48 * @var \Drupal\Core\PathProcessor\InboundPathProcessorInterface
50 protected $pathProcessor;
53 * Creates a new PathValidator.
55 * @param \Drupal\Core\Routing\AccessAwareRouterInterface $access_aware_router
56 * The access aware router.
57 * @param \Symfony\Component\Routing\Matcher\UrlMatcherInterface $access_unaware_router
58 * A router implementation which does not check access.
59 * @param \Drupal\Core\Session\AccountInterface $account
61 * @param \Drupal\Core\PathProcessor\InboundPathProcessorInterface $path_processor
64 public function __construct(AccessAwareRouterInterface $access_aware_router, UrlMatcherInterface $access_unaware_router, AccountInterface $account, InboundPathProcessorInterface $path_processor) {
65 $this->accessAwareRouter = $access_aware_router;
66 $this->accessUnawareRouter = $access_unaware_router;
67 $this->account = $account;
68 $this->pathProcessor = $path_processor;
74 public function isValid($path) {
75 return (bool) $this->getUrlIfValid($path);
81 public function getUrlIfValid($path) {
82 return $this->getUrl($path, TRUE);
88 public function getUrlIfValidWithoutAccessCheck($path) {
89 return $this->getUrl($path, FALSE);
93 * Helper for getUrlIfValid() and getUrlIfValidWithoutAccessCheck().
95 protected function getUrl($path, $access_check) {
96 $path = ltrim($path, '/');
98 $parsed_url = UrlHelper::parse($path);
101 if (!empty($parsed_url['query'])) {
102 $options['query'] = $parsed_url['query'];
104 if (!empty($parsed_url['fragment'])) {
105 $options['fragment'] = $parsed_url['fragment'];
108 if ($parsed_url['path'] == '<front>') {
109 return new Url('<front>', [], $options);
111 elseif ($parsed_url['path'] == '<none>') {
112 return new Url('<none>', [], $options);
114 elseif (UrlHelper::isExternal($path) && UrlHelper::isValid($path)) {
115 if (empty($parsed_url['path'])) {
118 return Url::fromUri($path);
121 $request = Request::create('/' . $path);
122 $attributes = $this->getPathAttributes($path, $request, $access_check);
128 $route_name = $attributes[RouteObjectInterface::ROUTE_NAME];
129 $route_parameters = $attributes['_raw_variables']->all();
131 return new Url($route_name, $route_parameters, $options + ['query' => $request->query->all()]);
135 * Gets the matched attributes for a given path.
137 * @param string $path
139 * @param \Symfony\Component\HttpFoundation\Request $request
140 * A request object with the given path.
141 * @param bool $access_check
142 * If FALSE then skip access check and check only whether the path is
146 * An array of request attributes of FALSE if an exception was thrown.
148 protected function getPathAttributes($path, Request $request, $access_check) {
149 if (!$access_check || $this->account->hasPermission('link to any page')) {
150 $router = $this->accessUnawareRouter;
153 $router = $this->accessAwareRouter;
156 $initial_request_context = $router->getContext() ? $router->getContext() : new RequestContext();
157 $path = $this->pathProcessor->processInbound('/' . $path, $request);
160 $request_context = new RequestContext();
161 $request_context->fromRequest($request);
162 $router->setContext($request_context);
163 $result = $router->match($path);
165 catch (ResourceNotFoundException $e) {
168 catch (ParamNotConvertedException $e) {
171 catch (AccessDeniedHttpException $e) {
174 catch (MethodNotAllowedException $e) {
178 $router->setContext($initial_request_context);