AccessAwareRouter.php 4.39 KB
Newer Older
1 2 3 4 5
<?php

namespace Drupal\Core\Routing;

use Drupal\Core\Access\AccessManagerInterface;
6
use Drupal\Core\Access\AccessResultReasonInterface;
7 8 9
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
10
use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
11
use Symfony\Component\Routing\RequestContext as SymfonyRequestContext;
12 13
use Symfony\Component\Routing\RequestContextAwareInterface;
use Symfony\Component\Routing\RouterInterface;
14 15 16 17 18 19 20

/**
 * A router class for Drupal with access check and upcasting.
 */
class AccessAwareRouter implements AccessAwareRouterInterface {

  /**
21
   * The router doing the actual routing.
22
   *
23
   * @var \Symfony\Component\Routing\Matcher\RequestMatcherInterface
24
   */
25
  protected $router;
26 27 28 29 30 31 32 33 34 35 36

  /**
   * The access manager.
   *
   * @var \Drupal\Core\Access\AccessManagerInterface
   */
  protected $accessManager;

  /**
   * The account to use in access checks.
   *
37
   * @var \Drupal\Core\Session\AccountInterface
38 39 40 41 42 43
   */
  protected $account;

  /**
   * Constructs a router for Drupal with access check and upcasting.
   *
44 45
   * @param \Symfony\Component\Routing\Matcher\RequestMatcherInterface $router
   *   The router doing the actual routing.
46 47 48 49 50
   * @param \Drupal\Core\Access\AccessManagerInterface $access_manager
   *   The access manager.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The account to use in access checks.
   */
51 52
  public function __construct(RequestMatcherInterface $router, AccessManagerInterface $access_manager, AccountInterface $account) {
    $this->router = $router;
53 54 55 56 57 58 59 60
    $this->accessManager = $access_manager;
    $this->account = $account;
  }

  /**
   * {@inheritdoc}
   */
  public function __call($name, $arguments) {
61 62
    // Ensure to call every other function to the router.
    return call_user_func_array([$this->router, $name], $arguments);
63 64 65 66 67
  }

  /**
   * {@inheritdoc}
   */
68
  public function setContext(SymfonyRequestContext $context) {
69 70 71
    if ($this->router instanceof RequestContextAwareInterface) {
      $this->router->setContext($context);
    }
72 73 74 75 76 77
  }

  /**
   * {@inheritdoc}
   */
  public function getContext() {
78 79 80
    if ($this->router instanceof RequestContextAwareInterface) {
      return $this->router->getContext();
    }
81 82 83 84 85 86 87 88 89
  }

  /**
   * {@inheritdoc}
   *
   * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
   *   Thrown when access checking failed.
   */
  public function matchRequest(Request $request) {
90
    $parameters = $this->router->matchRequest($request);
91 92 93 94 95 96 97 98 99 100 101 102 103 104
    $request->attributes->add($parameters);
    $this->checkAccess($request);
    // We can not return $parameters because the access check can change the
    // request attributes.
    return $request->attributes->all();
  }

  /**
   * Apply access check service to the route and parameters in the request.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request to access check.
   */
  protected function checkAccess(Request $request) {
105 106 107 108 109 110 111 112 113
    // The cacheability (if any) of this request's access check result must be
    // applied to the response.
    $access_result = $this->accessManager->checkRequest($request, $this->account, TRUE);
    // Allow a master request to set the access result for a subrequest: if an
    // access result attribute is already set, don't overwrite it.
    if (!$request->attributes->has(AccessAwareRouterInterface::ACCESS_RESULT)) {
      $request->attributes->set(AccessAwareRouterInterface::ACCESS_RESULT, $access_result);
    }
    if (!$access_result->isAllowed()) {
114
      throw new AccessDeniedHttpException($access_result instanceof AccessResultReasonInterface ? $access_result->getReason() : NULL);
115 116 117 118 119 120 121
    }
  }

  /**
   * {@inheritdoc}
   */
  public function getRouteCollection() {
122 123 124
    if ($this->router instanceof RouterInterface) {
      return $this->router->getRouteCollection();
    }
125 126 127 128 129
  }

  /**
   * {@inheritdoc}
   */
130
  public function generate($name, $parameters = [], $referenceType = self::ABSOLUTE_PATH) {
131 132 133
    if ($this->router instanceof UrlGeneratorInterface) {
      return $this->router->generate($name, $parameters, $referenceType);
    }
134 135 136 137 138 139 140 141 142 143 144 145 146
  }

  /**
   * {@inheritdoc}
   *
   * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
   *   Thrown when access checking failed.
   */
  public function match($pathinfo) {
    return $this->matchRequest(Request::create($pathinfo));
  }

}