Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\Core\Access;
|
Chris@0
|
4
|
Chris@0
|
5 use Drupal\Core\Routing\Access\AccessInterface;
|
Chris@0
|
6 use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
Chris@0
|
7 use Symfony\Component\DependencyInjection\ContainerAwareTrait;
|
Chris@0
|
8 use Symfony\Component\Routing\Route;
|
Chris@0
|
9 use Symfony\Component\Routing\RouteCollection;
|
Chris@0
|
10
|
Chris@0
|
11 /**
|
Chris@0
|
12 * Loads access checkers from the container.
|
Chris@0
|
13 */
|
Chris@0
|
14 class CheckProvider implements CheckProviderInterface, ContainerAwareInterface {
|
Chris@0
|
15
|
Chris@0
|
16 use ContainerAwareTrait;
|
Chris@0
|
17
|
Chris@0
|
18 /**
|
Chris@0
|
19 * Array of registered access check service ids.
|
Chris@0
|
20 *
|
Chris@0
|
21 * @var array
|
Chris@0
|
22 */
|
Chris@0
|
23 protected $checkIds = [];
|
Chris@0
|
24
|
Chris@0
|
25 /**
|
Chris@0
|
26 * Array of access check objects keyed by service id.
|
Chris@0
|
27 *
|
Chris@0
|
28 * @var \Drupal\Core\Routing\Access\AccessInterface[]
|
Chris@0
|
29 */
|
Chris@0
|
30 protected $checks;
|
Chris@0
|
31
|
Chris@0
|
32 /**
|
Chris@0
|
33 * Array of access check method names keyed by service ID.
|
Chris@0
|
34 *
|
Chris@0
|
35 * @var array
|
Chris@0
|
36 */
|
Chris@0
|
37 protected $checkMethods = [];
|
Chris@0
|
38
|
Chris@0
|
39 /**
|
Chris@0
|
40 * Array of access checks which only will be run on the incoming request.
|
Chris@0
|
41 */
|
Chris@0
|
42 protected $checksNeedsRequest = [];
|
Chris@0
|
43
|
Chris@0
|
44 /**
|
Chris@0
|
45 * An array to map static requirement keys to service IDs.
|
Chris@0
|
46 *
|
Chris@0
|
47 * @var array
|
Chris@0
|
48 */
|
Chris@0
|
49 protected $staticRequirementMap;
|
Chris@0
|
50
|
Chris@0
|
51 /**
|
Chris@0
|
52 * An array to map dynamic requirement keys to service IDs.
|
Chris@0
|
53 *
|
Chris@0
|
54 * @var array
|
Chris@0
|
55 */
|
Chris@0
|
56 protected $dynamicRequirementMap;
|
Chris@0
|
57
|
Chris@0
|
58 /**
|
Chris@0
|
59 * {@inheritdoc}
|
Chris@0
|
60 */
|
Chris@0
|
61 public function addCheckService($service_id, $service_method, array $applies_checks = [], $needs_incoming_request = FALSE) {
|
Chris@0
|
62 $this->checkIds[] = $service_id;
|
Chris@0
|
63 $this->checkMethods[$service_id] = $service_method;
|
Chris@0
|
64 if ($needs_incoming_request) {
|
Chris@0
|
65 $this->checksNeedsRequest[$service_id] = $service_id;
|
Chris@0
|
66 }
|
Chris@0
|
67 foreach ($applies_checks as $applies_check) {
|
Chris@0
|
68 $this->staticRequirementMap[$applies_check][] = $service_id;
|
Chris@0
|
69 }
|
Chris@0
|
70 }
|
Chris@0
|
71
|
Chris@0
|
72 /**
|
Chris@0
|
73 * {@inheritdoc}
|
Chris@0
|
74 */
|
Chris@0
|
75 public function getChecksNeedRequest() {
|
Chris@0
|
76 return $this->checksNeedsRequest;
|
Chris@0
|
77 }
|
Chris@0
|
78
|
Chris@0
|
79 /**
|
Chris@0
|
80 * {@inheritdoc}
|
Chris@0
|
81 */
|
Chris@0
|
82 public function setChecks(RouteCollection $routes) {
|
Chris@0
|
83 $this->loadDynamicRequirementMap();
|
Chris@0
|
84 foreach ($routes as $route) {
|
Chris@0
|
85 if ($checks = $this->applies($route)) {
|
Chris@0
|
86 $route->setOption('_access_checks', $checks);
|
Chris@0
|
87 }
|
Chris@0
|
88 }
|
Chris@0
|
89 }
|
Chris@0
|
90
|
Chris@0
|
91 /**
|
Chris@0
|
92 * {@inheritdoc}
|
Chris@0
|
93 */
|
Chris@0
|
94 public function loadCheck($service_id) {
|
Chris@0
|
95 if (empty($this->checks[$service_id])) {
|
Chris@0
|
96 if (!in_array($service_id, $this->checkIds)) {
|
Chris@0
|
97 throw new \InvalidArgumentException(sprintf('No check has been registered for %s', $service_id));
|
Chris@0
|
98 }
|
Chris@0
|
99
|
Chris@0
|
100 $check = $this->container->get($service_id);
|
Chris@0
|
101
|
Chris@0
|
102 if (!($check instanceof AccessInterface)) {
|
Chris@0
|
103 throw new AccessException('All access checks must implement AccessInterface.');
|
Chris@0
|
104 }
|
Chris@0
|
105 if (!is_callable([$check, $this->checkMethods[$service_id]])) {
|
Chris@0
|
106 throw new AccessException(sprintf('Access check method %s in service %s must be callable.', $this->checkMethods[$service_id], $service_id));
|
Chris@0
|
107 }
|
Chris@0
|
108
|
Chris@0
|
109 $this->checks[$service_id] = $check;
|
Chris@0
|
110 }
|
Chris@0
|
111 return [$this->checks[$service_id], $this->checkMethods[$service_id]];
|
Chris@0
|
112 }
|
Chris@0
|
113
|
Chris@0
|
114 /**
|
Chris@0
|
115 * Determine which registered access checks apply to a route.
|
Chris@0
|
116 *
|
Chris@0
|
117 * @param \Symfony\Component\Routing\Route $route
|
Chris@0
|
118 * The route to get list of access checks for.
|
Chris@0
|
119 *
|
Chris@0
|
120 * @return array
|
Chris@0
|
121 * An array of service ids for the access checks that apply to passed
|
Chris@0
|
122 * route.
|
Chris@0
|
123 */
|
Chris@0
|
124 protected function applies(Route $route) {
|
Chris@0
|
125 $checks = [];
|
Chris@0
|
126
|
Chris@0
|
127 // Iterate through map requirements from appliesTo() on access checkers.
|
Chris@0
|
128 // Only iterate through all checkIds if this is not used.
|
Chris@0
|
129 foreach ($route->getRequirements() as $key => $value) {
|
Chris@0
|
130 if (isset($this->staticRequirementMap[$key])) {
|
Chris@0
|
131 foreach ($this->staticRequirementMap[$key] as $service_id) {
|
Chris@0
|
132 $checks[] = $service_id;
|
Chris@0
|
133 }
|
Chris@0
|
134 }
|
Chris@0
|
135 }
|
Chris@0
|
136 // Finally, see if any dynamic access checkers apply.
|
Chris@0
|
137 foreach ($this->dynamicRequirementMap as $service_id) {
|
Chris@0
|
138 if ($this->checks[$service_id]->applies($route)) {
|
Chris@0
|
139 $checks[] = $service_id;
|
Chris@0
|
140 }
|
Chris@0
|
141 }
|
Chris@0
|
142
|
Chris@0
|
143 return $checks;
|
Chris@0
|
144 }
|
Chris@17
|
145
|
Chris@0
|
146 /**
|
Chris@0
|
147 * Compiles a mapping of requirement keys to access checker service IDs.
|
Chris@0
|
148 */
|
Chris@0
|
149 protected function loadDynamicRequirementMap() {
|
Chris@0
|
150 if (isset($this->dynamicRequirementMap)) {
|
Chris@0
|
151 return;
|
Chris@0
|
152 }
|
Chris@0
|
153
|
Chris@0
|
154 // Set them here, so we can use the isset() check above.
|
Chris@0
|
155 $this->dynamicRequirementMap = [];
|
Chris@0
|
156
|
Chris@0
|
157 foreach ($this->checkIds as $service_id) {
|
Chris@0
|
158 if (empty($this->checks[$service_id])) {
|
Chris@0
|
159 $this->loadCheck($service_id);
|
Chris@0
|
160 }
|
Chris@0
|
161
|
Chris@0
|
162 // Add the service ID to an array that will be iterated over.
|
Chris@0
|
163 if ($this->checks[$service_id] instanceof AccessCheckInterface) {
|
Chris@0
|
164 $this->dynamicRequirementMap[] = $service_id;
|
Chris@0
|
165 }
|
Chris@0
|
166 }
|
Chris@0
|
167 }
|
Chris@0
|
168
|
Chris@0
|
169 }
|