Mercurial > hg > cmmr2012-drupal-site
comparison vendor/symfony-cmf/routing/ContentAwareGenerator.php @ 0:c75dbcec494b
Initial commit from drush-created site
author | Chris Cannam |
---|---|
date | Thu, 05 Jul 2018 14:24:15 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c75dbcec494b |
---|---|
1 <?php | |
2 | |
3 /* | |
4 * This file is part of the Symfony CMF package. | |
5 * | |
6 * (c) 2011-2015 Symfony CMF | |
7 * | |
8 * For the full copyright and license information, please view the LICENSE | |
9 * file that was distributed with this source code. | |
10 */ | |
11 | |
12 namespace Symfony\Cmf\Component\Routing; | |
13 | |
14 use Doctrine\Common\Collections\Collection; | |
15 use Symfony\Component\Routing\Generator\UrlGeneratorInterface; | |
16 use Symfony\Component\Routing\Route as SymfonyRoute; | |
17 use Symfony\Component\Routing\Exception\RouteNotFoundException; | |
18 use Symfony\Component\Routing\RouteCollection; | |
19 | |
20 /** | |
21 * A generator that tries to generate routes from object, route names or | |
22 * content objects or names. | |
23 * | |
24 * @author Philippo de Santis | |
25 * @author David Buchmann | |
26 * @author Uwe Jäger | |
27 */ | |
28 class ContentAwareGenerator extends ProviderBasedGenerator | |
29 { | |
30 /** | |
31 * The locale to use when neither the parameters nor the request context | |
32 * indicate the locale to use. | |
33 * | |
34 * @var string | |
35 */ | |
36 protected $defaultLocale = null; | |
37 | |
38 /** | |
39 * The content repository used to find content by it's id | |
40 * This can be used to specify a parameter content_id when generating urls. | |
41 * | |
42 * This is optional and might not be initialized. | |
43 * | |
44 * @var ContentRepositoryInterface | |
45 */ | |
46 protected $contentRepository; | |
47 | |
48 /** | |
49 * Set an optional content repository to find content by ids. | |
50 * | |
51 * @param ContentRepositoryInterface $contentRepository | |
52 */ | |
53 public function setContentRepository(ContentRepositoryInterface $contentRepository) | |
54 { | |
55 $this->contentRepository = $contentRepository; | |
56 } | |
57 | |
58 /** | |
59 * {@inheritdoc} | |
60 * | |
61 * @param string $name ignored. | |
62 * @param array $parameters must either contain the field 'route' with a | |
63 * RouteObjectInterface or the field 'content_id' | |
64 * with the id of a document implementing | |
65 * RouteReferrersReadInterface. | |
66 * | |
67 * @throws RouteNotFoundException If there is no such route in the database | |
68 */ | |
69 public function generate($name, $parameters = array(), $absolute = UrlGeneratorInterface::ABSOLUTE_PATH) | |
70 { | |
71 if ($name instanceof SymfonyRoute) { | |
72 $route = $this->getBestLocaleRoute($name, $parameters); | |
73 } elseif (is_string($name) && $name) { | |
74 $route = $this->getRouteByName($name, $parameters); | |
75 } else { | |
76 $route = $this->getRouteByContent($name, $parameters); | |
77 } | |
78 | |
79 if (!$route instanceof SymfonyRoute) { | |
80 $hint = is_object($route) ? get_class($route) : gettype($route); | |
81 throw new RouteNotFoundException('Route of this document is not an instance of Symfony\Component\Routing\Route but: '.$hint); | |
82 } | |
83 | |
84 $this->unsetLocaleIfNotNeeded($route, $parameters); | |
85 | |
86 return parent::generate($route, $parameters, $absolute); | |
87 } | |
88 | |
89 /** | |
90 * Get the route by a string name. | |
91 * | |
92 * @param string $route | |
93 * @param array $parameters | |
94 * | |
95 * @return SymfonyRoute | |
96 * | |
97 * @throws RouteNotFoundException if there is no route found for the provided name | |
98 */ | |
99 protected function getRouteByName($name, array $parameters) | |
100 { | |
101 $route = $this->provider->getRouteByName($name); | |
102 if (empty($route)) { | |
103 throw new RouteNotFoundException('No route found for name: '.$name); | |
104 } | |
105 | |
106 return $this->getBestLocaleRoute($route, $parameters); | |
107 } | |
108 | |
109 /** | |
110 * Determine if there is a route with matching locale associated with the | |
111 * given route via associated content. | |
112 * | |
113 * @param SymfonyRoute $route | |
114 * @param array $parameters | |
115 * | |
116 * @return SymfonyRoute either the passed route or an alternative with better locale | |
117 */ | |
118 protected function getBestLocaleRoute(SymfonyRoute $route, $parameters) | |
119 { | |
120 if (!$route instanceof RouteObjectInterface) { | |
121 // this route has no content, we can't get the alternatives | |
122 return $route; | |
123 } | |
124 $locale = $this->getLocale($parameters); | |
125 if (!$this->checkLocaleRequirement($route, $locale)) { | |
126 $content = $route->getContent(); | |
127 if ($content instanceof RouteReferrersReadInterface) { | |
128 $routes = $content->getRoutes(); | |
129 $contentRoute = $this->getRouteByLocale($routes, $locale); | |
130 if ($contentRoute) { | |
131 return $contentRoute; | |
132 } | |
133 } | |
134 } | |
135 | |
136 return $route; | |
137 } | |
138 | |
139 /** | |
140 * Get the route based on the $name that is an object implementing | |
141 * RouteReferrersReadInterface or a content found in the content repository | |
142 * with the content_id specified in parameters that is an instance of | |
143 * RouteReferrersReadInterface. | |
144 * | |
145 * Called in generate when there is no route given in the parameters. | |
146 * | |
147 * If there is more than one route for the content, tries to find the | |
148 * first one that matches the _locale (provided in $parameters or otherwise | |
149 * defaulting to the request locale). | |
150 * | |
151 * If no route with matching locale is found, falls back to just return the | |
152 * first route. | |
153 * | |
154 * @param mixed $name | |
155 * @param array $parameters which should contain a content field containing | |
156 * a RouteReferrersReadInterface object | |
157 * | |
158 * @return SymfonyRoute the route instance | |
159 * | |
160 * @throws RouteNotFoundException if no route can be determined | |
161 */ | |
162 protected function getRouteByContent($name, &$parameters) | |
163 { | |
164 if ($name instanceof RouteReferrersReadInterface) { | |
165 $content = $name; | |
166 } elseif (isset($parameters['content_id']) | |
167 && null !== $this->contentRepository | |
168 ) { | |
169 $content = $this->contentRepository->findById($parameters['content_id']); | |
170 if (empty($content)) { | |
171 throw new RouteNotFoundException('The content repository found nothing at id '.$parameters['content_id']); | |
172 } | |
173 if (!$content instanceof RouteReferrersReadInterface) { | |
174 throw new RouteNotFoundException('Content repository did not return a RouteReferrersReadInterface instance for id '.$parameters['content_id']); | |
175 } | |
176 } else { | |
177 $hint = is_object($name) ? get_class($name) : gettype($name); | |
178 throw new RouteNotFoundException("The route name argument '$hint' is not RouteReferrersReadInterface instance and there is no 'content_id' parameter"); | |
179 } | |
180 | |
181 $routes = $content->getRoutes(); | |
182 if (empty($routes)) { | |
183 $hint = ($this->contentRepository && $this->contentRepository->getContentId($content)) | |
184 ? $this->contentRepository->getContentId($content) | |
185 : get_class($content); | |
186 throw new RouteNotFoundException('Content document has no route: '.$hint); | |
187 } | |
188 | |
189 unset($parameters['content_id']); | |
190 | |
191 $route = $this->getRouteByLocale($routes, $this->getLocale($parameters)); | |
192 if ($route) { | |
193 return $route; | |
194 } | |
195 | |
196 // if none matched, randomly return the first one | |
197 if ($routes instanceof Collection) { | |
198 return $routes->first(); | |
199 } | |
200 | |
201 return reset($routes); | |
202 } | |
203 | |
204 /** | |
205 * @param RouteCollection $routes | |
206 * @param string $locale | |
207 * | |
208 * @return bool|SymfonyRoute false if no route requirement matches the provided locale | |
209 */ | |
210 protected function getRouteByLocale($routes, $locale) | |
211 { | |
212 foreach ($routes as $route) { | |
213 if (!$route instanceof SymfonyRoute) { | |
214 continue; | |
215 } | |
216 | |
217 if ($this->checkLocaleRequirement($route, $locale)) { | |
218 return $route; | |
219 } | |
220 } | |
221 | |
222 return false; | |
223 } | |
224 | |
225 /** | |
226 * @param SymfonyRoute $route | |
227 * @param string $locale | |
228 * | |
229 * @return bool true if there is either no $locale, no _locale requirement | |
230 * on the route or if the requirement and the passed $locale | |
231 * match. | |
232 */ | |
233 private function checkLocaleRequirement(SymfonyRoute $route, $locale) | |
234 { | |
235 return empty($locale) | |
236 || !$route->getRequirement('_locale') | |
237 || preg_match('/'.$route->getRequirement('_locale').'/', $locale) | |
238 ; | |
239 } | |
240 | |
241 /** | |
242 * Determine the locale to be used with this request. | |
243 * | |
244 * @param array $parameters the parameters determined by the route | |
245 * | |
246 * @return string the locale following of the parameters or any other | |
247 * information the router has available. defaultLocale if no | |
248 * other locale can be determined. | |
249 */ | |
250 protected function getLocale($parameters) | |
251 { | |
252 if (isset($parameters['_locale'])) { | |
253 return $parameters['_locale']; | |
254 } | |
255 | |
256 if ($this->getContext()->hasParameter('_locale')) { | |
257 return $this->getContext()->getParameter('_locale'); | |
258 } | |
259 | |
260 return $this->defaultLocale; | |
261 } | |
262 | |
263 /** | |
264 * Overwrite the locale to be used by default if there is neither one in | |
265 * the parameters when building the route nor a request available (i.e. CLI). | |
266 * | |
267 * @param string $locale | |
268 */ | |
269 public function setDefaultLocale($locale) | |
270 { | |
271 $this->defaultLocale = $locale; | |
272 } | |
273 | |
274 /** | |
275 * We additionally support empty name and data in parameters and RouteAware content. | |
276 */ | |
277 public function supports($name) | |
278 { | |
279 return !$name || parent::supports($name) || $name instanceof RouteReferrersReadInterface; | |
280 } | |
281 | |
282 /** | |
283 * {@inheritdoc} | |
284 */ | |
285 public function getRouteDebugMessage($name, array $parameters = array()) | |
286 { | |
287 if (empty($name) && isset($parameters['content_id'])) { | |
288 return 'Content id '.$parameters['content_id']; | |
289 } | |
290 | |
291 if ($name instanceof RouteReferrersReadInterface) { | |
292 return 'Route aware content '.parent::getRouteDebugMessage($name, $parameters); | |
293 } | |
294 | |
295 return parent::getRouteDebugMessage($name, $parameters); | |
296 } | |
297 | |
298 /** | |
299 * If the _locale parameter is allowed by the requirements of the route | |
300 * and it is the default locale, remove it from the parameters so that we | |
301 * do not get an unneeded ?_locale= query string. | |
302 * | |
303 * @param SymfonyRoute $route The route being generated. | |
304 * @param array $parameters The parameters used, will be modified to | |
305 * remove the _locale field if needed. | |
306 */ | |
307 protected function unsetLocaleIfNotNeeded(SymfonyRoute $route, array &$parameters) | |
308 { | |
309 $locale = $this->getLocale($parameters); | |
310 if (null !== $locale) { | |
311 if (preg_match('/'.$route->getRequirement('_locale').'/', $locale) | |
312 && $locale == $route->getDefault('_locale') | |
313 ) { | |
314 $compiledRoute = $route->compile(); | |
315 if (!in_array('_locale', $compiledRoute->getVariables())) { | |
316 unset($parameters['_locale']); | |
317 } | |
318 } | |
319 } | |
320 } | |
321 } |