UrlGeneratorTest.php 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  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\RouteCollection;
  13. use Symfony\Component\Routing\Route;
  14. use Symfony\Component\Routing\Generator\UrlGenerator;
  15. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  16. use Symfony\Component\Routing\RequestContext;
  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 testGenerateForRouteWithInvalidUtf8Parameter()
  199. {
  200. $routes = $this->getRoutes('test', new Route('/testing/{foo}', array(), array('foo' => '\pL+'), array('utf8' => true)));
  201. $this->getGenerator($routes)->generate('test', array('foo' => 'abc123'), UrlGeneratorInterface::ABSOLUTE_URL);
  202. }
  203. /**
  204. * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
  205. */
  206. public function testRequiredParamAndEmptyPassed()
  207. {
  208. $routes = $this->getRoutes('test', new Route('/{slug}', array(), array('slug' => '.+')));
  209. $this->getGenerator($routes)->generate('test', array('slug' => ''));
  210. }
  211. public function testSchemeRequirementDoesNothingIfSameCurrentScheme()
  212. {
  213. $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('http')));
  214. $this->assertEquals('/app.php/', $this->getGenerator($routes)->generate('test'));
  215. $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('https')));
  216. $this->assertEquals('/app.php/', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test'));
  217. }
  218. public function testSchemeRequirementForcesAbsoluteUrl()
  219. {
  220. $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('https')));
  221. $this->assertEquals('https://localhost/app.php/', $this->getGenerator($routes)->generate('test'));
  222. $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('http')));
  223. $this->assertEquals('http://localhost/app.php/', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test'));
  224. }
  225. public function testSchemeRequirementCreatesUrlForFirstRequiredScheme()
  226. {
  227. $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('Ftp', 'https')));
  228. $this->assertEquals('ftp://localhost/app.php/', $this->getGenerator($routes)->generate('test'));
  229. }
  230. public function testPathWithTwoStartingSlashes()
  231. {
  232. $routes = $this->getRoutes('test', new Route('//path-and-not-domain'));
  233. // this must not generate '//path-and-not-domain' because that would be a network path
  234. $this->assertSame('/path-and-not-domain', $this->getGenerator($routes, array('BaseUrl' => ''))->generate('test'));
  235. }
  236. public function testNoTrailingSlashForMultipleOptionalParameters()
  237. {
  238. $routes = $this->getRoutes('test', new Route('/category/{slug1}/{slug2}/{slug3}', array('slug2' => null, 'slug3' => null)));
  239. $this->assertEquals('/app.php/category/foo', $this->getGenerator($routes)->generate('test', array('slug1' => 'foo')));
  240. }
  241. public function testWithAnIntegerAsADefaultValue()
  242. {
  243. $routes = $this->getRoutes('test', new Route('/{default}', array('default' => 0)));
  244. $this->assertEquals('/app.php/foo', $this->getGenerator($routes)->generate('test', array('default' => 'foo')));
  245. }
  246. public function testNullForOptionalParameterIsIgnored()
  247. {
  248. $routes = $this->getRoutes('test', new Route('/test/{default}', array('default' => 0)));
  249. $this->assertEquals('/app.php/test', $this->getGenerator($routes)->generate('test', array('default' => null)));
  250. }
  251. public function testQueryParamSameAsDefault()
  252. {
  253. $routes = $this->getRoutes('test', new Route('/test', array('page' => 1)));
  254. $this->assertSame('/app.php/test?page=2', $this->getGenerator($routes)->generate('test', array('page' => 2)));
  255. $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('page' => 1)));
  256. $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('page' => '1')));
  257. $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test'));
  258. }
  259. public function testArrayQueryParamSameAsDefault()
  260. {
  261. $routes = $this->getRoutes('test', new Route('/test', array('array' => array('foo', 'bar'))));
  262. $this->assertSame('/app.php/test?array%5B0%5D=bar&array%5B1%5D=foo', $this->getGenerator($routes)->generate('test', array('array' => array('bar', 'foo'))));
  263. $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'))));
  264. $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('array' => array('foo', 'bar'))));
  265. $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('array' => array(1 => 'bar', 0 => 'foo'))));
  266. $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test'));
  267. }
  268. public function testGenerateWithSpecialRouteName()
  269. {
  270. $routes = $this->getRoutes('$péß^a|', new Route('/bar'));
  271. $this->assertSame('/app.php/bar', $this->getGenerator($routes)->generate('$péß^a|'));
  272. }
  273. public function testUrlEncoding()
  274. {
  275. $expectedPath = '/app.php/@:%5B%5D/%28%29*%27%22%20+,;-._~%26%24%3C%3E|%7B%7D%25%5C%5E%60!%3Ffoo=bar%23id'
  276. .'/@:%5B%5D/%28%29*%27%22%20+,;-._~%26%24%3C%3E|%7B%7D%25%5C%5E%60!%3Ffoo=bar%23id'
  277. .'?query=%40%3A%5B%5D/%28%29%2A%27%22%20%2B%2C%3B-._~%26%24%3C%3E%7C%7B%7D%25%5C%5E%60%21%3Ffoo%3Dbar%23id';
  278. // This tests the encoding of reserved characters that are used for delimiting of URI components (defined in RFC 3986)
  279. // and other special ASCII chars. These chars are tested as static text path, variable path and query param.
  280. $chars = '@:[]/()*\'" +,;-._~&$<>|{}%\\^`!?foo=bar#id';
  281. $routes = $this->getRoutes('test', new Route("/$chars/{varpath}", array(), array('varpath' => '.+')));
  282. $this->assertSame($expectedPath, $this->getGenerator($routes)->generate('test', array(
  283. 'varpath' => $chars,
  284. 'query' => $chars,
  285. )));
  286. }
  287. public function testEncodingOfRelativePathSegments()
  288. {
  289. $routes = $this->getRoutes('test', new Route('/dir/../dir/..'));
  290. $this->assertSame('/app.php/dir/%2E%2E/dir/%2E%2E', $this->getGenerator($routes)->generate('test'));
  291. $routes = $this->getRoutes('test', new Route('/dir/./dir/.'));
  292. $this->assertSame('/app.php/dir/%2E/dir/%2E', $this->getGenerator($routes)->generate('test'));
  293. $routes = $this->getRoutes('test', new Route('/a./.a/a../..a/...'));
  294. $this->assertSame('/app.php/a./.a/a../..a/...', $this->getGenerator($routes)->generate('test'));
  295. }
  296. public function testAdjacentVariables()
  297. {
  298. $routes = $this->getRoutes('test', new Route('/{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => '\d+')));
  299. $generator = $this->getGenerator($routes);
  300. $this->assertSame('/app.php/foo123', $generator->generate('test', array('x' => 'foo', 'y' => '123')));
  301. $this->assertSame('/app.php/foo123bar.xml', $generator->generate('test', array('x' => 'foo', 'y' => '123', 'z' => 'bar', '_format' => 'xml')));
  302. // The default requirement for 'x' should not allow the separator '.' in this case because it would otherwise match everything
  303. // and following optional variables like _format could never match.
  304. $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Routing\Exception\InvalidParameterException');
  305. $generator->generate('test', array('x' => 'do.t', 'y' => '123', 'z' => 'bar', '_format' => 'xml'));
  306. }
  307. public function testOptionalVariableWithNoRealSeparator()
  308. {
  309. $routes = $this->getRoutes('test', new Route('/get{what}', array('what' => 'All')));
  310. $generator = $this->getGenerator($routes);
  311. $this->assertSame('/app.php/get', $generator->generate('test'));
  312. $this->assertSame('/app.php/getSites', $generator->generate('test', array('what' => 'Sites')));
  313. }
  314. public function testRequiredVariableWithNoRealSeparator()
  315. {
  316. $routes = $this->getRoutes('test', new Route('/get{what}Suffix'));
  317. $generator = $this->getGenerator($routes);
  318. $this->assertSame('/app.php/getSitesSuffix', $generator->generate('test', array('what' => 'Sites')));
  319. }
  320. public function testDefaultRequirementOfVariable()
  321. {
  322. $routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
  323. $generator = $this->getGenerator($routes);
  324. $this->assertSame('/app.php/index.mobile.html', $generator->generate('test', array('page' => 'index', '_format' => 'mobile.html')));
  325. }
  326. /**
  327. * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
  328. */
  329. public function testDefaultRequirementOfVariableDisallowsSlash()
  330. {
  331. $routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
  332. $this->getGenerator($routes)->generate('test', array('page' => 'index', '_format' => 'sl/ash'));
  333. }
  334. /**
  335. * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
  336. */
  337. public function testDefaultRequirementOfVariableDisallowsNextSeparator()
  338. {
  339. $routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
  340. $this->getGenerator($routes)->generate('test', array('page' => 'do.t', '_format' => 'html'));
  341. }
  342. public function testWithHostDifferentFromContext()
  343. {
  344. $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
  345. $this->assertEquals('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', array('name' => 'Fabien', 'locale' => 'fr')));
  346. }
  347. public function testWithHostSameAsContext()
  348. {
  349. $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
  350. $this->assertEquals('/app.php/Fabien', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test', array('name' => 'Fabien', 'locale' => 'fr')));
  351. }
  352. public function testWithHostSameAsContextAndAbsolute()
  353. {
  354. $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
  355. $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));
  356. }
  357. /**
  358. * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
  359. */
  360. public function testUrlWithInvalidParameterInHost()
  361. {
  362. $routes = $this->getRoutes('test', new Route('/', array(), array('foo' => 'bar'), array(), '{foo}.example.com'));
  363. $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), UrlGeneratorInterface::ABSOLUTE_PATH);
  364. }
  365. /**
  366. * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
  367. */
  368. public function testUrlWithInvalidParameterInHostWhenParamHasADefaultValue()
  369. {
  370. $routes = $this->getRoutes('test', new Route('/', array('foo' => 'bar'), array('foo' => 'bar'), array(), '{foo}.example.com'));
  371. $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), UrlGeneratorInterface::ABSOLUTE_PATH);
  372. }
  373. /**
  374. * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
  375. */
  376. public function testUrlWithInvalidParameterEqualsDefaultValueInHost()
  377. {
  378. $routes = $this->getRoutes('test', new Route('/', array('foo' => 'baz'), array('foo' => 'bar'), array(), '{foo}.example.com'));
  379. $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), UrlGeneratorInterface::ABSOLUTE_PATH);
  380. }
  381. public function testUrlWithInvalidParameterInHostInNonStrictMode()
  382. {
  383. $routes = $this->getRoutes('test', new Route('/', array(), array('foo' => 'bar'), array(), '{foo}.example.com'));
  384. $generator = $this->getGenerator($routes);
  385. $generator->setStrictRequirements(false);
  386. $this->assertNull($generator->generate('test', array('foo' => 'baz'), UrlGeneratorInterface::ABSOLUTE_PATH));
  387. }
  388. public function testHostIsCaseInsensitive()
  389. {
  390. $routes = $this->getRoutes('test', new Route('/', array(), array('locale' => 'en|de|fr'), array(), '{locale}.FooBar.com'));
  391. $generator = $this->getGenerator($routes);
  392. $this->assertSame('//EN.FooBar.com/app.php/', $generator->generate('test', array('locale' => 'EN'), UrlGeneratorInterface::NETWORK_PATH));
  393. }
  394. public function testGenerateNetworkPath()
  395. {
  396. $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com', array('http')));
  397. $this->assertSame('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test',
  398. array('name' => 'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::NETWORK_PATH), 'network path with different host'
  399. );
  400. $this->assertSame('//fr.example.com/app.php/Fabien?query=string', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test',
  401. array('name' => 'Fabien', 'locale' => 'fr', 'query' => 'string'), UrlGeneratorInterface::NETWORK_PATH), 'network path although host same as context'
  402. );
  403. $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test',
  404. array('name' => 'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::NETWORK_PATH), 'absolute URL because scheme requirement does not match context'
  405. );
  406. $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test',
  407. array('name' => 'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::ABSOLUTE_URL), 'absolute URL with same scheme because it is requested'
  408. );
  409. }
  410. public function testGenerateRelativePath()
  411. {
  412. $routes = new RouteCollection();
  413. $routes->add('article', new Route('/{author}/{article}/'));
  414. $routes->add('comments', new Route('/{author}/{article}/comments'));
  415. $routes->add('host', new Route('/{article}', array(), array(), array(), '{author}.example.com'));
  416. $routes->add('scheme', new Route('/{author}/blog', array(), array(), array(), '', array('https')));
  417. $routes->add('unrelated', new Route('/about'));
  418. $generator = $this->getGenerator($routes, array('host' => 'example.com', 'pathInfo' => '/fabien/symfony-is-great/'));
  419. $this->assertSame('comments', $generator->generate('comments',
  420. array('author' => 'fabien', 'article' => 'symfony-is-great'), UrlGeneratorInterface::RELATIVE_PATH)
  421. );
  422. $this->assertSame('comments?page=2', $generator->generate('comments',
  423. array('author' => 'fabien', 'article' => 'symfony-is-great', 'page' => 2), UrlGeneratorInterface::RELATIVE_PATH)
  424. );
  425. $this->assertSame('../twig-is-great/', $generator->generate('article',
  426. array('author' => 'fabien', 'article' => 'twig-is-great'), UrlGeneratorInterface::RELATIVE_PATH)
  427. );
  428. $this->assertSame('../../bernhard/forms-are-great/', $generator->generate('article',
  429. array('author' => 'bernhard', 'article' => 'forms-are-great'), UrlGeneratorInterface::RELATIVE_PATH)
  430. );
  431. $this->assertSame('//bernhard.example.com/app.php/forms-are-great', $generator->generate('host',
  432. array('author' => 'bernhard', 'article' => 'forms-are-great'), UrlGeneratorInterface::RELATIVE_PATH)
  433. );
  434. $this->assertSame('https://example.com/app.php/bernhard/blog', $generator->generate('scheme',
  435. array('author' => 'bernhard'), UrlGeneratorInterface::RELATIVE_PATH)
  436. );
  437. $this->assertSame('../../about', $generator->generate('unrelated',
  438. array(), UrlGeneratorInterface::RELATIVE_PATH)
  439. );
  440. }
  441. /**
  442. * @dataProvider provideRelativePaths
  443. */
  444. public function testGetRelativePath($sourcePath, $targetPath, $expectedPath)
  445. {
  446. $this->assertSame($expectedPath, UrlGenerator::getRelativePath($sourcePath, $targetPath));
  447. }
  448. public function provideRelativePaths()
  449. {
  450. return array(
  451. array(
  452. '/same/dir/',
  453. '/same/dir/',
  454. '',
  455. ),
  456. array(
  457. '/same/file',
  458. '/same/file',
  459. '',
  460. ),
  461. array(
  462. '/',
  463. '/file',
  464. 'file',
  465. ),
  466. array(
  467. '/',
  468. '/dir/file',
  469. 'dir/file',
  470. ),
  471. array(
  472. '/dir/file.html',
  473. '/dir/different-file.html',
  474. 'different-file.html',
  475. ),
  476. array(
  477. '/same/dir/extra-file',
  478. '/same/dir/',
  479. './',
  480. ),
  481. array(
  482. '/parent/dir/',
  483. '/parent/',
  484. '../',
  485. ),
  486. array(
  487. '/parent/dir/extra-file',
  488. '/parent/',
  489. '../',
  490. ),
  491. array(
  492. '/a/b/',
  493. '/x/y/z/',
  494. '../../x/y/z/',
  495. ),
  496. array(
  497. '/a/b/c/d/e',
  498. '/a/c/d',
  499. '../../../c/d',
  500. ),
  501. array(
  502. '/a/b/c//',
  503. '/a/b/c/',
  504. '../',
  505. ),
  506. array(
  507. '/a/b/c/',
  508. '/a/b/c//',
  509. './/',
  510. ),
  511. array(
  512. '/root/a/b/c/',
  513. '/root/x/b/c/',
  514. '../../../x/b/c/',
  515. ),
  516. array(
  517. '/a/b/c/d/',
  518. '/a',
  519. '../../../../a',
  520. ),
  521. array(
  522. '/special-chars/sp%20ce/1€/mäh/e=mc²',
  523. '/special-chars/sp%20ce/1€/<µ>/e=mc²',
  524. '../<µ>/e=mc²',
  525. ),
  526. array(
  527. 'not-rooted',
  528. 'dir/file',
  529. 'dir/file',
  530. ),
  531. array(
  532. '//dir/',
  533. '',
  534. '../../',
  535. ),
  536. array(
  537. '/dir/',
  538. '/dir/file:with-colon',
  539. './file:with-colon',
  540. ),
  541. array(
  542. '/dir/',
  543. '/dir/subdir/file:with-colon',
  544. 'subdir/file:with-colon',
  545. ),
  546. array(
  547. '/dir/',
  548. '/dir/:subdir/',
  549. './:subdir/',
  550. ),
  551. );
  552. }
  553. public function testFragmentsCanBeAppendedToUrls()
  554. {
  555. $routes = $this->getRoutes('test', new Route('/testing'));
  556. $url = $this->getGenerator($routes)->generate('test', array('_fragment' => 'frag ment'), UrlGeneratorInterface::ABSOLUTE_PATH);
  557. $this->assertEquals('/app.php/testing#frag%20ment', $url);
  558. $url = $this->getGenerator($routes)->generate('test', array('_fragment' => '0'), UrlGeneratorInterface::ABSOLUTE_PATH);
  559. $this->assertEquals('/app.php/testing#0', $url);
  560. }
  561. public function testFragmentsDoNotEscapeValidCharacters()
  562. {
  563. $routes = $this->getRoutes('test', new Route('/testing'));
  564. $url = $this->getGenerator($routes)->generate('test', array('_fragment' => '?/'), UrlGeneratorInterface::ABSOLUTE_PATH);
  565. $this->assertEquals('/app.php/testing#?/', $url);
  566. }
  567. public function testFragmentsCanBeDefinedAsDefaults()
  568. {
  569. $routes = $this->getRoutes('test', new Route('/testing', array('_fragment' => 'fragment')));
  570. $url = $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_PATH);
  571. $this->assertEquals('/app.php/testing#fragment', $url);
  572. }
  573. protected function getGenerator(RouteCollection $routes, array $parameters = array(), $logger = null)
  574. {
  575. $context = new RequestContext('/app.php');
  576. foreach ($parameters as $key => $value) {
  577. $method = 'set'.$key;
  578. $context->$method($value);
  579. }
  580. return new UrlGenerator($routes, $context, $logger);
  581. }
  582. protected function getRoutes($name, Route $route)
  583. {
  584. $routes = new RouteCollection();
  585. $routes->add($name, $route);
  586. return $routes;
  587. }
  588. }