Mercurial > hg > isophonics-drupal-site
comparison core/lib/Drupal/Core/Routing/RouteBuilder.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | af1871eacc83 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\Core\Routing; | |
4 | |
5 use Drupal\Core\Access\CheckProviderInterface; | |
6 use Drupal\Core\Controller\ControllerResolverInterface; | |
7 use Drupal\Core\Discovery\YamlDiscovery; | |
8 use Drupal\Core\Extension\ModuleHandlerInterface; | |
9 use Drupal\Core\Lock\LockBackendInterface; | |
10 use Drupal\Core\DestructableInterface; | |
11 use Symfony\Component\EventDispatcher\Event; | |
12 use Symfony\Component\EventDispatcher\EventDispatcherInterface; | |
13 use Symfony\Component\Routing\RouteCollection; | |
14 use Symfony\Component\Routing\Route; | |
15 | |
16 /** | |
17 * Managing class for rebuilding the router table. | |
18 */ | |
19 class RouteBuilder implements RouteBuilderInterface, DestructableInterface { | |
20 | |
21 /** | |
22 * The dumper to which we should send collected routes. | |
23 * | |
24 * @var \Drupal\Core\Routing\MatcherDumperInterface | |
25 */ | |
26 protected $dumper; | |
27 | |
28 /** | |
29 * The used lock backend instance. | |
30 * | |
31 * @var \Drupal\Core\Lock\LockBackendInterface | |
32 */ | |
33 protected $lock; | |
34 | |
35 /** | |
36 * The event dispatcher to notify of routes. | |
37 * | |
38 * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface | |
39 */ | |
40 protected $dispatcher; | |
41 | |
42 /** | |
43 * The module handler. | |
44 * | |
45 * @var \Drupal\Core\Extension\ModuleHandlerInterface | |
46 */ | |
47 protected $moduleHandler; | |
48 | |
49 /** | |
50 * The controller resolver. | |
51 * | |
52 * @var \Drupal\Core\Controller\ControllerResolverInterface | |
53 */ | |
54 protected $controllerResolver; | |
55 | |
56 /** | |
57 * The route collection during the rebuild. | |
58 * | |
59 * @var \Symfony\Component\Routing\RouteCollection | |
60 */ | |
61 protected $routeCollection; | |
62 | |
63 /** | |
64 * Flag that indicates if we are currently rebuilding the routes. | |
65 * | |
66 * @var bool | |
67 */ | |
68 protected $building = FALSE; | |
69 | |
70 /** | |
71 * Flag that indicates if we should rebuild at the end of the request. | |
72 * | |
73 * @var bool | |
74 */ | |
75 protected $rebuildNeeded = FALSE; | |
76 | |
77 /** | |
78 * The check provider. | |
79 * | |
80 * @var \Drupal\Core\Access\CheckProviderInterface | |
81 */ | |
82 protected $checkProvider; | |
83 | |
84 /** | |
85 * Constructs the RouteBuilder using the passed MatcherDumperInterface. | |
86 * | |
87 * @param \Drupal\Core\Routing\MatcherDumperInterface $dumper | |
88 * The matcher dumper used to store the route information. | |
89 * @param \Drupal\Core\Lock\LockBackendInterface $lock | |
90 * The lock backend. | |
91 * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher | |
92 * The event dispatcher to notify of routes. | |
93 * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler | |
94 * The module handler. | |
95 * @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver | |
96 * The controller resolver. | |
97 * @param \Drupal\Core\Access\CheckProviderInterface $check_provider | |
98 * The check provider. | |
99 */ | |
100 public function __construct(MatcherDumperInterface $dumper, LockBackendInterface $lock, EventDispatcherInterface $dispatcher, ModuleHandlerInterface $module_handler, ControllerResolverInterface $controller_resolver, CheckProviderInterface $check_provider) { | |
101 $this->dumper = $dumper; | |
102 $this->lock = $lock; | |
103 $this->dispatcher = $dispatcher; | |
104 $this->moduleHandler = $module_handler; | |
105 $this->controllerResolver = $controller_resolver; | |
106 $this->checkProvider = $check_provider; | |
107 } | |
108 | |
109 /** | |
110 * {@inheritdoc} | |
111 */ | |
112 public function setRebuildNeeded() { | |
113 $this->rebuildNeeded = TRUE; | |
114 } | |
115 | |
116 /** | |
117 * {@inheritdoc} | |
118 */ | |
119 public function rebuild() { | |
120 if ($this->building) { | |
121 throw new \RuntimeException('Recursive router rebuild detected.'); | |
122 } | |
123 | |
124 if (!$this->lock->acquire('router_rebuild')) { | |
125 // Wait for another request that is already doing this work. | |
126 // We choose to block here since otherwise the routes might not be | |
127 // available, resulting in a 404. | |
128 $this->lock->wait('router_rebuild'); | |
129 return FALSE; | |
130 } | |
131 | |
132 $this->building = TRUE; | |
133 | |
134 $collection = new RouteCollection(); | |
135 foreach ($this->getRouteDefinitions() as $routes) { | |
136 // The top-level 'routes_callback' is a list of methods in controller | |
137 // syntax, see \Drupal\Core\Controller\ControllerResolver. These methods | |
138 // should return a set of \Symfony\Component\Routing\Route objects, either | |
139 // in an associative array keyed by the route name, which will be iterated | |
140 // over and added to the collection for this provider, or as a new | |
141 // \Symfony\Component\Routing\RouteCollection object, which will be added | |
142 // to the collection. | |
143 if (isset($routes['route_callbacks'])) { | |
144 foreach ($routes['route_callbacks'] as $route_callback) { | |
145 $callback = $this->controllerResolver->getControllerFromDefinition($route_callback); | |
146 if ($callback_routes = call_user_func($callback)) { | |
147 // If a RouteCollection is returned, add the whole collection. | |
148 if ($callback_routes instanceof RouteCollection) { | |
149 $collection->addCollection($callback_routes); | |
150 } | |
151 // Otherwise, add each Route object individually. | |
152 else { | |
153 foreach ($callback_routes as $name => $callback_route) { | |
154 $collection->add($name, $callback_route); | |
155 } | |
156 } | |
157 } | |
158 } | |
159 unset($routes['route_callbacks']); | |
160 } | |
161 foreach ($routes as $name => $route_info) { | |
162 $route_info += [ | |
163 'defaults' => [], | |
164 'requirements' => [], | |
165 'options' => [], | |
166 'host' => NULL, | |
167 'schemes' => [], | |
168 'methods' => [], | |
169 'condition' => '', | |
170 ]; | |
171 | |
172 $route = new Route($route_info['path'], $route_info['defaults'], $route_info['requirements'], $route_info['options'], $route_info['host'], $route_info['schemes'], $route_info['methods'], $route_info['condition']); | |
173 $collection->add($name, $route); | |
174 } | |
175 } | |
176 | |
177 // DYNAMIC is supposed to be used to add new routes based upon all the | |
178 // static defined ones. | |
179 $this->dispatcher->dispatch(RoutingEvents::DYNAMIC, new RouteBuildEvent($collection)); | |
180 | |
181 // ALTER is the final step to alter all the existing routes. We cannot stop | |
182 // people from adding new routes here, but we define two separate steps to | |
183 // make it clear. | |
184 $this->dispatcher->dispatch(RoutingEvents::ALTER, new RouteBuildEvent($collection)); | |
185 | |
186 $this->checkProvider->setChecks($collection); | |
187 | |
188 $this->dumper->addRoutes($collection); | |
189 $this->dumper->dump(); | |
190 | |
191 $this->lock->release('router_rebuild'); | |
192 $this->dispatcher->dispatch(RoutingEvents::FINISHED, new Event()); | |
193 $this->building = FALSE; | |
194 | |
195 $this->rebuildNeeded = FALSE; | |
196 | |
197 return TRUE; | |
198 } | |
199 | |
200 /** | |
201 * {@inheritdoc} | |
202 */ | |
203 public function rebuildIfNeeded() { | |
204 if ($this->rebuildNeeded) { | |
205 return $this->rebuild(); | |
206 } | |
207 return FALSE; | |
208 } | |
209 | |
210 /** | |
211 * {@inheritdoc} | |
212 */ | |
213 public function destruct() { | |
214 // Rebuild routes only once at the end of the request lifecycle to not | |
215 // trigger multiple rebuilds and also make the page more responsive for the | |
216 // user. | |
217 $this->rebuildIfNeeded(); | |
218 } | |
219 | |
220 /** | |
221 * Retrieves all defined routes from .routing.yml files. | |
222 * | |
223 * @return array | |
224 * The defined routes, keyed by provider. | |
225 */ | |
226 protected function getRouteDefinitions() { | |
227 // Always instantiate a new YamlDiscovery object so that we always search on | |
228 // the up-to-date list of modules. | |
229 $discovery = new YamlDiscovery('routing', $this->moduleHandler->getModuleDirectories()); | |
230 return $discovery->findAll(); | |
231 } | |
232 | |
233 } |