PathValidator.php

Same filename in other branches
  1. 9 core/lib/Drupal/Core/Path/PathValidator.php
  2. 10 core/lib/Drupal/Core/Path/PathValidator.php
  3. 11.x core/lib/Drupal/Core/Path/PathValidator.php

Namespace

Drupal\Core\Path

File

core/lib/Drupal/Core/Path/PathValidator.php

View source
<?php

namespace Drupal\Core\Path;

use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\ParamConverter\ParamNotConvertedException;
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Drupal\Core\Routing\AccessAwareRouterInterface;
use Drupal\Core\Routing\RequestContext;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\Matcher\UrlMatcherInterface;

/**
 * Provides a default path validator and access checker.
 */
class PathValidator implements PathValidatorInterface {
    
    /**
     * The access aware router.
     *
     * @var \Drupal\Core\Routing\AccessAwareRouterInterface
     */
    protected $accessAwareRouter;
    
    /**
     * A router implementation which does not check access.
     *
     * @var \Symfony\Component\Routing\Matcher\UrlMatcherInterface
     */
    protected $accessUnawareRouter;
    
    /**
     * The current user.
     *
     * @var \Drupal\Core\Session\AccountInterface
     */
    protected $account;
    
    /**
     * The path processor.
     *
     * @var \Drupal\Core\PathProcessor\InboundPathProcessorInterface
     */
    protected $pathProcessor;
    
    /**
     * Creates a new PathValidator.
     *
     * @param \Drupal\Core\Routing\AccessAwareRouterInterface $access_aware_router
     *   The access aware router.
     * @param \Symfony\Component\Routing\Matcher\UrlMatcherInterface $access_unaware_router
     *   A router implementation which does not check access.
     * @param \Drupal\Core\Session\AccountInterface $account
     *   The current user.
     * @param \Drupal\Core\PathProcessor\InboundPathProcessorInterface $path_processor
     *   The path processor;
     */
    public function __construct(AccessAwareRouterInterface $access_aware_router, UrlMatcherInterface $access_unaware_router, AccountInterface $account, InboundPathProcessorInterface $path_processor) {
        $this->accessAwareRouter = $access_aware_router;
        $this->accessUnawareRouter = $access_unaware_router;
        $this->account = $account;
        $this->pathProcessor = $path_processor;
    }
    
    /**
     * {@inheritdoc}
     */
    public function isValid($path) {
        return (bool) $this->getUrlIfValid($path);
    }
    
    /**
     * {@inheritdoc}
     */
    public function getUrlIfValid($path) {
        return $this->getUrl($path, TRUE);
    }
    
    /**
     * {@inheritdoc}
     */
    public function getUrlIfValidWithoutAccessCheck($path) {
        return $this->getUrl($path, FALSE);
    }
    
    /**
     * Helper for getUrlIfValid() and getUrlIfValidWithoutAccessCheck().
     */
    protected function getUrl($path, $access_check) {
        $path = ltrim($path, '/');
        $parsed_url = UrlHelper::parse($path);
        $options = [];
        if (!empty($parsed_url['query'])) {
            $options['query'] = $parsed_url['query'];
        }
        if (!empty($parsed_url['fragment'])) {
            $options['fragment'] = $parsed_url['fragment'];
        }
        if ($parsed_url['path'] == '<front>') {
            return new Url('<front>', [], $options);
        }
        elseif ($parsed_url['path'] == '<none>') {
            return new Url('<none>', [], $options);
        }
        elseif (UrlHelper::isExternal($path) && UrlHelper::isValid($path)) {
            if (empty($parsed_url['path'])) {
                return FALSE;
            }
            return Url::fromUri($path);
        }
        $request = Request::create('/' . $path);
        $attributes = $this->getPathAttributes($path, $request, $access_check);
        if (!$attributes) {
            return FALSE;
        }
        $route_name = $attributes[RouteObjectInterface::ROUTE_NAME];
        $route_parameters = $attributes['_raw_variables']->all();
        return new Url($route_name, $route_parameters, $options + [
            'query' => $request->query
                ->all(),
        ]);
    }
    
    /**
     * Gets the matched attributes for a given path.
     *
     * @param string $path
     *   The path to check.
     * @param \Symfony\Component\HttpFoundation\Request $request
     *   A request object with the given path.
     * @param bool $access_check
     *   If FALSE then skip access check and check only whether the path is
     *   valid.
     *
     * @return array|bool
     *   An array of request attributes of FALSE if an exception was thrown.
     */
    protected function getPathAttributes($path, Request $request, $access_check) {
        if (!$access_check || $this->account
            ->hasPermission('link to any page')) {
            $router = $this->accessUnawareRouter;
        }
        else {
            $router = $this->accessAwareRouter;
        }
        $initial_request_context = $router->getContext() ? $router->getContext() : new RequestContext();
        $path = $this->pathProcessor
            ->processInbound('/' . $path, $request);
        try {
            $request_context = new RequestContext();
            $request_context->fromRequest($request);
            $router->setContext($request_context);
            $result = $router->match($path);
        } catch (ResourceNotFoundException $e) {
            $result = FALSE;
        } catch (ParamNotConvertedException $e) {
            $result = FALSE;
        } catch (AccessDeniedHttpException $e) {
            $result = FALSE;
        } catch (MethodNotAllowedException $e) {
            $result = FALSE;
        }
        $router->setContext($initial_request_context);
        return $result;
    }

}

Classes

Title Deprecated Summary
PathValidator Provides a default path validator and access checker.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.