UrlGeneratorTest.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Routing\Tests\Generator;
  11. use PHPUnit\Framework\TestCase;
  12. use Symfony\Component\Routing\Generator\UrlGenerator;
  13. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  14. use Symfony\Component\Routing\RequestContext;
  15. use Symfony\Component\Routing\Route;
  16. use Symfony\Component\Routing\RouteCollection;
  17. class UrlGeneratorTest extends TestCase
  18. {
  19. public function testAbsoluteUrlWithPort80()
  20. {
  21. $routes = $this->getRoutes('test', new Route('/testing'));
  22. $url = $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL);
  23. $this->assertEquals('http://localhost/app.php/testing', $url);
  24. }
  25. public function testAbsoluteSecureUrlWithPort443()
  26. {
  27. $routes = $this->getRoutes('test', new Route('/testing'));
  28. $url = $this->getGenerator($routes, array('scheme' => 'https'))->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL);
  29. $this->assertEquals('https://localhost/app.php/testing', $url);
  30. }
  31. public function testAbsoluteUrlWithNonStandardPort()
  32. {
  33. $routes = $this->getRoutes('test', new Route('/testing'));
  34. $url = $this->getGenerator($routes, array('httpPort' => 8080))->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL);
  35. $this->assertEquals('http://localhost:8080/app.php/testing', $url);
  36. }
  37. public function testAbsoluteSecureUrlWithNonStandardPort()
  38. {
  39. $routes = $this->getRoutes('test', new Route('/testing'));
  40. $url = $this->getGenerator($routes, array('httpsPort' => 8080, 'scheme' => 'https'))->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL);
  41. $this->assertEquals('https://localhost:8080/app.php/testing', $url);
  42. }
  43. public function testRelativeUrlWithoutParameters()
  44. {
  45. $routes = $this->getRoutes('test', new Route('/testing'));
  46. $url = $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_PATH);
  47. $this->assertEquals('/app.php/testing', $url);
  48. }
  49. public function testRelativeUrlWithParameter()
  50. {
  51. $routes = $this->getRoutes('test', new Route('/testing/{foo}'));
  52. $url = $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_PATH);
  53. $this->assertEquals('/app.php/testing/bar', $url);
  54. }
  55. public function testRelativeUrlWithNullParameter()
  56. {
  57. $routes = $this->getRoutes('test', new Route('/testing.{format}', array('format' => null)));
  58. $url = $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_PATH);
  59. $this->assertEquals('/app.php/testing', $url);
  60. }
  61. /**
  62. * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
  63. */
  64. public function testRelativeUrlWithNullParameterButNotOptional()
  65. {
  66. $routes = $this->getRoutes('test', new Route('/testing/{foo}/bar', array('foo' => null)));
  67. // This must raise an exception because the default requirement for "foo" is "[^/]+" which is not met with these params.
  68. // Generating path "/testing//bar" would be wrong as matching this route would fail.
  69. $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_PATH);
  70. }
  71. public function testRelativeUrlWithOptionalZeroParameter()
  72. {
  73. $routes = $this->getRoutes('test', new Route('/testing/{page}'));
  74. $url = $this->getGenerator($routes)->generate('test', array('page' => 0), UrlGeneratorInterface::ABSOLUTE_PATH);
  75. $this->assertEquals('/app.php/testing/0', $url);
  76. }
  77. public function testNotPassedOptionalParameterInBetween()
  78. {
  79. $routes = $this->getRoutes('test', new Route('/{slug}/{page}', array('slug' => 'index', 'page' => 0)));
  80. $this->assertSame('/app.php/index/1', $this->getGenerator($routes)->generate('test', array('page' => 1)));
  81. $this->assertSame('/app.php/', $this->getGenerator($routes)->generate('test'));
  82. }
  83. public function testRelativeUrlWithExtraParameters()
  84. {
  85. $routes = $this->getRoutes('test', new Route('/testing'));
  86. $url = $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_PATH);
  87. $this->assertEquals('/app.php/testing?foo=bar', $url);
  88. }
  89. public function testAbsoluteUrlWithExtraParameters()
  90. {
  91. $routes = $this->getRoutes('test', new Route('/testing'));
  92. $url = $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_URL);
  93. $this->assertEquals('http://localhost/app.php/testing?foo=bar', $url);
  94. }
  95. public function testUrlWithNullExtraParameters()
  96. {
  97. $routes = $this->getRoutes('test', new Route('/testing'));
  98. $url = $this->getGenerator($routes)->generate('test', array('foo' => null), UrlGeneratorInterface::ABSOLUTE_URL);
  99. $this->assertEquals('http://localhost/app.php/testing', $url);
  100. }
  101. public function testUrlWithExtraParametersFromGlobals()
  102. {
  103. $routes = $this->getRoutes('test', new Route('/testing'));
  104. $generator = $this->getGenerator($routes);
  105. $context = new RequestContext('/app.php');
  106. $context->setParameter('bar', 'bar');
  107. $generator->setContext($context);
  108. $url = $generator->generate('test', array('foo' => 'bar'));
  109. $this->assertEquals('/app.php/testing?foo=bar', $url);
  110. }
  111. public function testUrlWithGlobalParameter()
  112. {
  113. $routes = $this->getRoutes('test', new Route('/testing/{foo}'));
  114. $generator = $this->getGenerator($routes);
  115. $context = new RequestContext('/app.php');
  116. $context->setParameter('foo', 'bar');
  117. $generator->setContext($context);
  118. $url = $generator->generate('test', array());
  119. $this->assertEquals('/app.php/testing/bar', $url);
  120. }
  121. public function testGlobalParameterHasHigherPriorityThanDefault()
  122. {
  123. $routes = $this->getRoutes('test', new Route('/{_locale}', array('_locale' => 'en')));
  124. $generator = $this->getGenerator($routes);
  125. $context = new RequestContext('/app.php');
  126. $context->setParameter('_locale', 'de');
  127. $generator->setContext($context);
  128. $url = $generator->generate('test', array());
  129. $this->assertSame('/app.php/de', $url);
  130. }
  131. /**
  132. * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException
  133. */
  134. public function testGenerateWithoutRoutes()
  135. {
  136. $routes = $this->getRoutes('foo', new Route('/testing/{foo}'));
  137. $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL);
  138. }
  139. /**
  140. * @expectedException \Symfony\Component\Routing\Exception\MissingMandatoryParametersException
  141. */
  142. public function testGenerateForRouteWithoutMandatoryParameter()
  143. {
  144. $routes = $this->getRoutes('test', new Route('/testing/{foo}'));
  145. $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL);
  146. }
  147. /**
  148. * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
  149. */
  150. public function testGenerateForRouteWithInvalidOptionalParameter()
  151. {
  152. $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
  153. $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_URL);
  154. }
  155. /**
  156. * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
  157. */
  158. public function testGenerateForRouteWithInvalidParameter()
  159. {
  160. $routes = $this->getRoutes('test', new Route('/testing/{foo}', array(), array('foo' => '1|2')));
  161. $this->getGenerator($routes)->generate('test', array('foo' => '0'), UrlGeneratorInterface::ABSOLUTE_URL);
  162. }
  163. public function testGenerateForRouteWithInvalidOptionalParameterNonStrict()
  164. {
  165. $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
  166. $generator = $this->getGenerator($routes);
  167. $generator->setStrictRequirements(false);
  168. $this->assertNull($generator->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_URL));
  169. }
  170. public function testGenerateForRouteWithInvalidOptionalParameterNonStrictWithLogger()
  171. {
  172. $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
  173. $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
  174. $logger->expects($this->once())
  175. ->method('error');
  176. $generator = $this->getGenerator($routes, array(), $logger);
  177. $generator->setStrictRequirements(false);
  178. $this->assertNull($generator->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_URL));
  179. }
  180. public function testGenerateForRouteWithInvalidParameterButDisabledRequirementsCheck()
  181. {
  182. $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
  183. $generator = $this->getGenerator($routes);
  184. $generator->setStrictRequirements(null);
  185. $this->assertSame('/app.php/testing/bar', $generator->generate('test', array('foo' => 'bar')));
  186. }
  187. /**
  188. * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
  189. */
  190. public function testGenerateForRouteWithInvalidMandatoryParameter()
  191. {
  192. $routes = $this->getRoutes('test', new Route('/testing/{foo}', array(), array('foo' => 'd+')));
  193. $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_URL);
  194. }
  195. /**
  196. * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
  197. */
  198. public function testRequiredParamAndEmptyPassed()
  199. {
  200. $routes = $this->getRoutes('test', new Route('/{slug}', array(), array('slug' => '.+')));
  201. $this->getGenerator($routes)->generate('test', array('slug' => ''));
  202. }
  203. public function testSchemeRequirementDoesNothingIfSameCurrentScheme()
  204. {
  205. $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('http')));
  206. $this->assertEquals('/app.php/', $this->getGenerator($routes)->generate('test'));
  207. $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('https')));
  208. $this->assertEquals('/app.php/', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test'));
  209. }
  210. public function testSchemeRequirementForcesAbsoluteUrl()
  211. {
  212. $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('https')));
  213. $this->assertEquals('https://localhost/app.php/', $this->getGenerator($routes)->generate('test'));
  214. $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('http')));
  215. $this->assertEquals('http://localhost/app.php/', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test'));
  216. }
  217. public function testSchemeRequirementCreatesUrlForFirstRequiredScheme()
  218. {
  219. $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('Ftp', 'https')));
  220. $this->assertEquals('ftp://localhost/app.php/', $this->getGenerator($routes)->generate('test'));
  221. }
  222. public function testPathWithTwoStartingSlashes()
  223. {
  224. $routes = $this->getRoutes('test', new Route('//path-and-not-domain'));
  225. // this must not generate '//path-and-not-domain' because that would be a network path
  226. $this->assertSame('/path-and-not-domain', $this->getGenerator($routes, array('BaseUrl' => ''))->generate('test'));
  227. }
  228. public function testNoTrailingSlashForMultipleOptionalParameters()
  229. {
  230. $routes = $this->getRoutes('test', new Route('/category/{slug1}/{slug2}/{slug3}', array('slug2' => null, 'slug3' => null)));
  231. $this->assertEquals('/app.php/category/foo', $this->getGenerator($routes)->generate('test', array('slug1' => 'foo')));
  232. }
  233. public function testWithAnIntegerAsADefaultValue()
  234. {
  235. $routes = $this->getRoutes('test', new Route('/{default}', array('default' => 0)));
  236. $this->assertEquals('/app.php/foo', $this->getGenerator($routes)->generate('test', array('default' => 'foo')));
  237. }
  238. public function testNullForOptionalParameterIsIgnored()
  239. {
  240. $routes = $this->getRoutes('test', new Route('/test/{default}', array('default' => 0)));
  241. $this->assertEquals('/app.php/test', $this->getGenerator($routes)->generate('test', array('default' => null)));
  242. }
  243. public function testQueryParamSameAsDefault()
  244. {
  245. $routes = $this->getRoutes('test', new Route('/test', array('page' => 1)));
  246. $this->assertSame('/app.php/test?page=2', $this->getGenerator($routes)->generate('test', array('page' => 2)));
  247. $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('page' => 1)));
  248. $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('page' => '1')));
  249. $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test'));
  250. }
  251. public function testArrayQueryParamSameAsDefault()
  252. {
  253. $routes = $this->getRoutes('test', new Route('/test', array('array' => array('foo', 'bar'))));
  254. $this->assertSame('/app.php/test?array%5B0%5D=bar&array%5B1%5D=foo', $this->getGenerator($routes)->generate('test', array('array' => array('bar', 'foo'))));
  255. $this->assertSame('/app.php/test?array%5Ba%5D=foo&array%5Bb%5D=bar', $this->getGenerator($routes)->generate('test', array('array' => array('a' => 'foo', 'b' => 'bar'))));
  256. $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('array' => array('foo', 'bar'))));
  257. $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('array' => array(1 => 'bar', 0 => 'foo'))));
  258. $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test'));
  259. }
  260. public function testGenerateWithSpecialRouteName()
  261. {
  262. $routes = $this->getRoutes('$péß^a|', new Route('/bar'));
  263. $this->assertSame('/app.php/bar', $this->getGenerator($routes)->generate('$péß^a|'));
  264. }
  265. public function testUrlEncoding()
  266. {
  267. // This tests the encoding of reserved characters that are used for delimiting of URI components (defined in RFC 3986)
  268. // and other special ASCII chars. These chars are tested as static text path, variable path and query param.
  269. $chars = '@:[]/()*\'" +,;-._~&$<>|{}%\\^`!?foo=bar#id';
  270. $routes = $this->getRoutes('test', new Route("/$chars/{varpath}", array(), array('varpath' => '.+')));
  271. $this->assertSame('/app.php/@:%5B%5D/%28%29*%27%22%20+,;-._~%26%24%3C%3E|%7B%7D%25%5C%5E%60!%3Ffoo=bar%23id'
  272. .'/@:%5B%5D/%28%29*%27%22%20+,;-._~%26%24%3C%3E|%7B%7D%25%5C%5E%60!%3Ffoo=bar%23id'
  273. .'?query=%40%3A%5B%5D/%28%29%2A%27%22+%2B%2C%3B-._%7E%26%24%3C%3E%7C%7B%7D%25%5C%5E%60%21%3Ffoo%3Dbar%23id',
  274. $this->getGenerator($routes)->generate('test', array(
  275. 'varpath' => $chars,
  276. 'query' => $chars,
  277. ))
  278. );
  279. }
  280. public function testEncodingOfRelativePathSegments()
  281. {
  282. $routes = $this->getRoutes('test', new Route('/dir/../dir/..'));
  283. $this->assertSame('/app.php/dir/%2E%2E/dir/%2E%2E', $this->getGenerator($routes)->generate('test'));
  284. $routes = $this->getRoutes('test', new Route('/dir/./dir/.'));
  285. $this->assertSame('/app.php/dir/%2E/dir/%2E', $this->getGenerator($routes)->generate('test'));
  286. $routes = $this->getRoutes('test', new Route('/a./.a/a../..a/...'));
  287. $this->assertSame('/app.php/a./.a/a../..a/...', $this->getGenerator($routes)->generate('test'));
  288. }
  289. public function testAdjacentVariables()
  290. {
  291. $routes = $this->getRoutes('test', new Route('/{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => '\d+')));
  292. $generator = $this->getGenerator($routes);
  293. $this->assertSame('/app.php/foo123', $generator->generate('test', array('x' => 'foo', 'y' => '123')));
  294. $this->assertSame('/app.php/foo123bar.xml', $generator->generate('test', array('x' => 'foo', 'y' => '123', 'z' => 'bar', '_format' => 'xml')));
  295. // The default requirement for 'x' should not allow the separator '.' in this case because it would otherwise match everything
  296. // and following optional variables like _format could never match.
  297. $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Routing\Exception\InvalidParameterException');
  298. $generator->generate('test', array('x' => 'do.t', 'y' => '123', 'z' => 'bar', '_format' => 'xml'));
  299. }
  300. public function testOptionalVariableWithNoRealSeparator()
  301. {
  302. $routes = $this->getRoutes('test', new Route('/get{what}', array('what' => 'All')));
  303. $generator = $this->getGenerator($routes);
  304. $this->assertSame('/app.php/get', $generator->generate('test'));
  305. $this->assertSame('/app.php/getSites', $generator->generate('test', array('what' => 'Sites')));
  306. }
  307. public function testRequiredVariableWithNoRealSeparator()
  308. {
  309. $routes = $this->getRoutes('test', new Route('/get{what}Suffix'));
  310. $generator = $this->getGenerator($routes);
  311. $this->assertSame('/app.php/getSitesSuffix', $generator->generate('test', array('what' => 'Sites')));
  312. }
  313. public function testDefaultRequirementOfVariable()
  314. {
  315. $routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
  316. $generator = $this->getGenerator($routes);
  317. $this->assertSame('/app.php/index.mobile.html', $generator->generate('test', array('page' => 'index', '_format' => 'mobile.html')));
  318. }
  319. /**
  320. * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
  321. */
  322. public function testDefaultRequirementOfVariableDisallowsSlash()
  323. {
  324. $routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
  325. $this->getGenerator($routes)->generate('test', array('page' => 'index', '_format' => 'sl/ash'));
  326. }
  327. /**
  328. * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
  329. */
  330. public function testDefaultRequirementOfVariableDisallowsNextSeparator()
  331. {
  332. $routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
  333. $this->getGenerator($routes)->generate('test', array('page' => 'do.t', '_format' => 'html'));
  334. }
  335. public function testWithHostDifferentFromContext()
  336. {
  337. $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
  338. $this->assertEquals('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', array('name' => 'Fabien', 'locale' => 'fr')));
  339. }
  340. public function testWithHostSameAsContext()
  341. {
  342. $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
  343. $this->assertEquals('/app.php/Fabien', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test', array('name' => 'Fabien', 'locale' => 'fr')));
  344. }
  345. public function testWithHostSameAsContextAndAbsolute()
  346. {
  347. $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
  348. $this->assertEquals('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test', array('name' => 'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::ABSOLUTE_URL));
  349. }
  350. /**
  351. * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
  352. */
  353. public function testUrlWithInvalidParameterInHost()
  354. {
  355. $routes = $this->getRoutes('test', new Route('/', array(), array('foo' => 'bar'), array(), '{foo}.example.com'));
  356. $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), UrlGeneratorInterface::ABSOLUTE_PATH);
  357. }
  358. /**
  359. * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
  360. */
  361. public function testUrlWithInvalidParameterInHostWhenParamHasADefaultValue()
  362. {
  363. $routes = $this->getRoutes('test', new Route('/', array('foo' => 'bar'), array('foo' => 'bar'), array(), '{foo}.example.com'));
  364. $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), UrlGeneratorInterface::ABSOLUTE_PATH);
  365. }
  366. /**
  367. * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
  368. */
  369. public function testUrlWithInvalidParameterEqualsDefaultValueInHost()
  370. {
  371. $routes = $this->getRoutes('test', new Route('/', array('foo' => 'baz'), array('foo' => 'bar'), array(), '{foo}.example.com'));
  372. $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), UrlGeneratorInterface::ABSOLUTE_PATH);
  373. }
  374. public function testUrlWithInvalidParameterInHostInNonStrictMode()
  375. {
  376. $routes = $this->getRoutes('test', new Route('/', array(), array('foo' => 'bar'), array(), '{foo}.example.com'));
  377. $generator = $this->getGenerator($routes);
  378. $generator->setStrictRequirements(false);
  379. $this->assertNull($generator->generate('test', array('foo' => 'baz'), UrlGeneratorInterface::ABSOLUTE_PATH));
  380. }
  381. public function testHostIsCaseInsensitive()
  382. {
  383. $routes = $this->getRoutes('test', new Route('/', array(), array('locale' => 'en|de|fr'), array(), '{locale}.FooBar.com'));
  384. $generator = $this->getGenerator($routes);
  385. $this->assertSame('//EN.FooBar.com/app.php/', $generator->generate('test', array('locale' => 'EN'), UrlGeneratorInterface::NETWORK_PATH));
  386. }
  387. public function testDefaultHostIsUsedWhenContextHostIsEmpty()
  388. {
  389. $routes = $this->getRoutes('test', new Route('/route', array('domain' => 'my.fallback.host'), array('domain' => '.+'), array(), '{domain}', array('http')));
  390. $generator = $this->getGenerator($routes);
  391. $generator->getContext()->setHost('');
  392. $this->assertSame('http://my.fallback.host/app.php/route', $generator->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL));
  393. }
  394. public function testDefaultHostIsUsedWhenContextHostIsEmptyAndSchemeIsNot()
  395. {
  396. $routes = $this->getRoutes('test', new Route('/route', array('domain' => 'my.fallback.host'), array('domain' => '.+'), array(), '{domain}', array('http', 'https')));
  397. $generator = $this->getGenerator($routes);
  398. $generator->getContext()->setHost('');
  399. $generator->getContext()->setScheme('https');
  400. $this->assertSame('https://my.fallback.host/app.php/route', $generator->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL));
  401. }
  402. public function testAbsoluteUrlFallbackToRelativeIfHostIsEmptyAndSchemeIsNot()
  403. {
  404. $routes = $this->getRoutes('test', new Route('/route', array(), array(), array(), '', array('http', 'https')));
  405. $generator = $this->getGenerator($routes);
  406. $generator->getContext()->setHost('');
  407. $generator->getContext()->setScheme('https');
  408. $this->assertSame('/app.php/route', $generator->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL));
  409. }
  410. /**
  411. * @group legacy
  412. */
  413. public function testLegacyGenerateNetworkPath()
  414. {
  415. $routes = $this->getRoutes('test', new Route('/{name}', array(), array('_scheme' => 'http'), array(), '{locale}.example.com'));
  416. $this->assertSame('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test',
  417. array('name' => 'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::NETWORK_PATH), 'network path with different host'
  418. );
  419. $this->assertSame('//fr.example.com/app.php/Fabien?query=string', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test',
  420. array('name' => 'Fabien', 'locale' => 'fr', 'query' => 'string'), UrlGeneratorInterface::NETWORK_PATH), 'network path although host same as context'
  421. );
  422. $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test',
  423. array('name' => 'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::NETWORK_PATH), 'absolute URL because scheme requirement does not match context'
  424. );
  425. $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test',
  426. array('name' => 'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::ABSOLUTE_URL), 'absolute URL with same scheme because it is requested'
  427. );
  428. }
  429. public function testGenerateNetworkPath()
  430. {
  431. $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com', array('http')));
  432. $this->assertSame('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test',
  433. array('name' => 'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::NETWORK_PATH), 'network path with different host'
  434. );
  435. $this->assertSame('//fr.example.com/app.php/Fabien?query=string', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test',
  436. array('name' => 'Fabien', 'locale' => 'fr', 'query' => 'string'), UrlGeneratorInterface::NETWORK_PATH), 'network path although host same as context'
  437. );
  438. $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test',
  439. array('name' => 'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::NETWORK_PATH), 'absolute URL because scheme requirement does not match context'
  440. );
  441. $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test',
  442. array('name' => 'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::ABSOLUTE_URL), 'absolute URL with same scheme because it is requested'
  443. );
  444. }
  445. public function testGenerateRelativePath()
  446. {
  447. $routes = new RouteCollection();
  448. $routes->add('article', new Route('/{author}/{article}/'));
  449. $routes->add('comments', new Route('/{author}/{article}/comments'));
  450. $routes->add('host', new Route('/{article}', array(), array(), array(), '{author}.example.com'));
  451. $routes->add('scheme', new Route('/{author}/blog', array(), array(), array(), '', array('https')));
  452. $routes->add('unrelated', new Route('/about'));
  453. $generator = $this->getGenerator($routes, array('host' => 'example.com', 'pathInfo' => '/fabien/symfony-is-great/'));
  454. $this->assertSame('comments', $generator->generate('comments',
  455. array('author' => 'fabien', 'article' => 'symfony-is-great'), UrlGeneratorInterface::RELATIVE_PATH)
  456. );
  457. $this->assertSame('comments?page=2', $generator->generate('comments',
  458. array('author' => 'fabien', 'article' => 'symfony-is-great', 'page' => 2), UrlGeneratorInterface::RELATIVE_PATH)
  459. );
  460. $this->assertSame('../twig-is-great/', $generator->generate('article',
  461. array('author' => 'fabien', 'article' => 'twig-is-great'), UrlGeneratorInterface::RELATIVE_PATH)
  462. );
  463. $this->assertSame('../../bernhard/forms-are-great/', $generator->generate('article',
  464. array('author' => 'bernhard', 'article' => 'forms-are-great'), UrlGeneratorInterface::RELATIVE_PATH)
  465. );
  466. $this->assertSame('//bernhard.example.com/app.php/forms-are-great', $generator->generate('host',
  467. array('author' => 'bernhard', 'article' => 'forms-are-great'), UrlGeneratorInterface::RELATIVE_PATH)
  468. );
  469. $this->assertSame('https://example.com/app.php/bernhard/blog', $generator->generate('scheme',
  470. array('author' => 'bernhard'), UrlGeneratorInterface::RELATIVE_PATH)
  471. );
  472. $this->assertSame('../../about', $generator->generate('unrelated',
  473. array(), UrlGeneratorInterface::RELATIVE_PATH)
  474. );
  475. }
  476. /**
  477. * @dataProvider provideRelativePaths
  478. */
  479. public function testGetRelativePath($sourcePath, $targetPath, $expectedPath)
  480. {
  481. $this->assertSame($expectedPath, UrlGenerator::getRelativePath($sourcePath, $targetPath));
  482. }
  483. public function provideRelativePaths()
  484. {
  485. return array(
  486. array(
  487. '/same/dir/',
  488. '/same/dir/',
  489. '',
  490. ),
  491. array(
  492. '/same/file',
  493. '/same/file',
  494. '',
  495. ),
  496. array(
  497. '/',
  498. '/file',
  499. 'file',
  500. ),
  501. array(
  502. '/',
  503. '/dir/file',
  504. 'dir/file',
  505. ),
  506. array(
  507. '/dir/file.html',
  508. '/dir/different-file.html',
  509. 'different-file.html',
  510. ),
  511. array(
  512. '/same/dir/extra-file',
  513. '/same/dir/',
  514. './',
  515. ),
  516. array(
  517. '/parent/dir/',
  518. '/parent/',
  519. '../',
  520. ),
  521. array(
  522. '/parent/dir/extra-file',
  523. '/parent/',
  524. '../',
  525. ),
  526. array(
  527. '/a/b/',
  528. '/x/y/z/',
  529. '../../x/y/z/',
  530. ),
  531. array(
  532. '/a/b/c/d/e',
  533. '/a/c/d',
  534. '../../../c/d',
  535. ),
  536. array(
  537. '/a/b/c//',
  538. '/a/b/c/',
  539. '../',
  540. ),
  541. array(
  542. '/a/b/c/',
  543. '/a/b/c//',
  544. './/',
  545. ),
  546. array(
  547. '/root/a/b/c/',
  548. '/root/x/b/c/',
  549. '../../../x/b/c/',
  550. ),
  551. array(
  552. '/a/b/c/d/',
  553. '/a',
  554. '../../../../a',
  555. ),
  556. array(
  557. '/special-chars/sp%20ce/1€/mäh/e=mc²',
  558. '/special-chars/sp%20ce/1€/<µ>/e=mc²',
  559. '../<µ>/e=mc²',
  560. ),
  561. array(
  562. 'not-rooted',
  563. 'dir/file',
  564. 'dir/file',
  565. ),
  566. array(
  567. '//dir/',
  568. '',
  569. '../../',
  570. ),
  571. array(
  572. '/dir/',
  573. '/dir/file:with-colon',
  574. './file:with-colon',
  575. ),
  576. array(
  577. '/dir/',
  578. '/dir/subdir/file:with-colon',
  579. 'subdir/file:with-colon',
  580. ),
  581. array(
  582. '/dir/',
  583. '/dir/:subdir/',
  584. './:subdir/',
  585. ),
  586. );
  587. }
  588. protected function getGenerator(RouteCollection $routes, array $parameters = array(), $logger = null)
  589. {
  590. $context = new RequestContext('/app.php');
  591. foreach ($parameters as $key => $value) {
  592. $method = 'set'.$key;
  593. $context->$method($value);
  594. }
  595. return new UrlGenerator($routes, $context, $logger);
  596. }
  597. protected function getRoutes($name, Route $route)
  598. {
  599. $routes = new RouteCollection();
  600. $routes->add($name, $route);
  601. return $routes;
  602. }
  603. }