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