AccessAwareRouter.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. <?php
  2. namespace Drupal\Core\Routing;
  3. use Drupal\Core\Access\AccessManagerInterface;
  4. use Drupal\Core\Access\AccessResultReasonInterface;
  5. use Drupal\Core\Session\AccountInterface;
  6. use Symfony\Component\HttpFoundation\Request;
  7. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  8. use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
  9. use Symfony\Component\Routing\RequestContext as SymfonyRequestContext;
  10. use Symfony\Component\Routing\RequestContextAwareInterface;
  11. use Symfony\Component\Routing\RouterInterface;
  12. /**
  13. * A router class for Drupal with access check and upcasting.
  14. */
  15. class AccessAwareRouter implements AccessAwareRouterInterface {
  16. /**
  17. * The router doing the actual routing.
  18. *
  19. * @var \Symfony\Component\Routing\Matcher\RequestMatcherInterface
  20. */
  21. protected $router;
  22. /**
  23. * The access manager.
  24. *
  25. * @var \Drupal\Core\Access\AccessManagerInterface
  26. */
  27. protected $accessManager;
  28. /**
  29. * The account to use in access checks.
  30. *
  31. * @var \Drupal\Core\Session\AccountInterface;
  32. */
  33. protected $account;
  34. /**
  35. * Constructs a router for Drupal with access check and upcasting.
  36. *
  37. * @param \Symfony\Component\Routing\Matcher\RequestMatcherInterface $router
  38. * The router doing the actual routing.
  39. * @param \Drupal\Core\Access\AccessManagerInterface $access_manager
  40. * The access manager.
  41. * @param \Drupal\Core\Session\AccountInterface $account
  42. * The account to use in access checks.
  43. */
  44. public function __construct(RequestMatcherInterface $router, AccessManagerInterface $access_manager, AccountInterface $account) {
  45. $this->router = $router;
  46. $this->accessManager = $access_manager;
  47. $this->account = $account;
  48. }
  49. /**
  50. * {@inheritdoc}
  51. */
  52. public function __call($name, $arguments) {
  53. // Ensure to call every other function to the router.
  54. return call_user_func_array([$this->router, $name], $arguments);
  55. }
  56. /**
  57. * {@inheritdoc}
  58. */
  59. public function setContext(SymfonyRequestContext $context) {
  60. if ($this->router instanceof RequestContextAwareInterface) {
  61. $this->router->setContext($context);
  62. }
  63. }
  64. /**
  65. * {@inheritdoc}
  66. */
  67. public function getContext() {
  68. if ($this->router instanceof RequestContextAwareInterface) {
  69. return $this->router->getContext();
  70. }
  71. }
  72. /**
  73. * {@inheritdoc}
  74. *
  75. * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
  76. * Thrown when access checking failed.
  77. */
  78. public function matchRequest(Request $request) {
  79. $parameters = $this->router->matchRequest($request);
  80. $request->attributes->add($parameters);
  81. $this->checkAccess($request);
  82. // We can not return $parameters because the access check can change the
  83. // request attributes.
  84. return $request->attributes->all();
  85. }
  86. /**
  87. * Apply access check service to the route and parameters in the request.
  88. *
  89. * @param \Symfony\Component\HttpFoundation\Request $request
  90. * The request to access check.
  91. */
  92. protected function checkAccess(Request $request) {
  93. // The cacheability (if any) of this request's access check result must be
  94. // applied to the response.
  95. $access_result = $this->accessManager->checkRequest($request, $this->account, TRUE);
  96. // Allow a master request to set the access result for a subrequest: if an
  97. // access result attribute is already set, don't overwrite it.
  98. if (!$request->attributes->has(AccessAwareRouterInterface::ACCESS_RESULT)) {
  99. $request->attributes->set(AccessAwareRouterInterface::ACCESS_RESULT, $access_result);
  100. }
  101. if (!$access_result->isAllowed()) {
  102. throw new AccessDeniedHttpException($access_result instanceof AccessResultReasonInterface ? $access_result->getReason() : NULL);
  103. }
  104. }
  105. /**
  106. * {@inheritdoc}
  107. */
  108. public function getRouteCollection() {
  109. if ($this->router instanceof RouterInterface) {
  110. return $this->router->getRouteCollection();
  111. }
  112. }
  113. /**
  114. * {@inheritdoc}
  115. */
  116. public function generate($name, $parameters = [], $referenceType = self::ABSOLUTE_PATH) {
  117. if ($this->router instanceof UrlGeneratorInterface) {
  118. return $this->router->generate($name, $parameters, $referenceType);
  119. }
  120. }
  121. /**
  122. * {@inheritdoc}
  123. *
  124. * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
  125. * Thrown when access checking failed.
  126. */
  127. public function match($pathinfo) {
  128. return $this->matchRequest(Request::create($pathinfo));
  129. }
  130. }