PhpMatcherDumperTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  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\Matcher\Dumper;
  11. use PHPUnit\Framework\TestCase;
  12. use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper;
  13. use Symfony\Component\Routing\Matcher\RedirectableUrlMatcherInterface;
  14. use Symfony\Component\Routing\Matcher\UrlMatcher;
  15. use Symfony\Component\Routing\RequestContext;
  16. use Symfony\Component\Routing\Route;
  17. use Symfony\Component\Routing\RouteCollection;
  18. class PhpMatcherDumperTest extends TestCase
  19. {
  20. /**
  21. * @var string
  22. */
  23. private $matcherClass;
  24. /**
  25. * @var string
  26. */
  27. private $dumpPath;
  28. protected function setUp()
  29. {
  30. parent::setUp();
  31. $this->matcherClass = uniqid('ProjectUrlMatcher');
  32. $this->dumpPath = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'php_matcher.'.$this->matcherClass.'.php';
  33. }
  34. protected function tearDown()
  35. {
  36. parent::tearDown();
  37. @unlink($this->dumpPath);
  38. }
  39. /**
  40. * @expectedException \LogicException
  41. */
  42. public function testDumpWhenSchemeIsUsedWithoutAProperDumper()
  43. {
  44. $collection = new RouteCollection();
  45. $collection->add('secure', new Route(
  46. '/secure',
  47. array(),
  48. array(),
  49. array(),
  50. '',
  51. array('https')
  52. ));
  53. $dumper = new PhpMatcherDumper($collection);
  54. $dumper->dump();
  55. }
  56. public function testRedirectPreservesUrlEncoding()
  57. {
  58. $collection = new RouteCollection();
  59. $collection->add('foo', new Route('/foo:bar/'));
  60. $class = $this->generateDumpedMatcher($collection, true);
  61. $matcher = $this->getMockBuilder($class)
  62. ->setMethods(array('redirect'))
  63. ->setConstructorArgs(array(new RequestContext()))
  64. ->getMock();
  65. $matcher->expects($this->once())->method('redirect')->with('/foo%3Abar/', 'foo');
  66. $matcher->match('/foo%3Abar');
  67. }
  68. /**
  69. * @dataProvider getRouteCollections
  70. */
  71. public function testDump(RouteCollection $collection, $fixture, $options = array())
  72. {
  73. $basePath = __DIR__.'/../../Fixtures/dumper/';
  74. $dumper = new PhpMatcherDumper($collection);
  75. $this->assertStringEqualsFile($basePath.$fixture, $dumper->dump($options), '->dump() correctly dumps routes as optimized PHP code.');
  76. }
  77. public function getRouteCollections()
  78. {
  79. /* test case 1 */
  80. $collection = new RouteCollection();
  81. $collection->add('overridden', new Route('/overridden'));
  82. // defaults and requirements
  83. $collection->add('foo', new Route(
  84. '/foo/{bar}',
  85. array('def' => 'test'),
  86. array('bar' => 'baz|symfony')
  87. ));
  88. // method requirement
  89. $collection->add('bar', new Route(
  90. '/bar/{foo}',
  91. array(),
  92. array(),
  93. array(),
  94. '',
  95. array(),
  96. array('GET', 'head')
  97. ));
  98. // GET method requirement automatically adds HEAD as valid
  99. $collection->add('barhead', new Route(
  100. '/barhead/{foo}',
  101. array(),
  102. array(),
  103. array(),
  104. '',
  105. array(),
  106. array('GET')
  107. ));
  108. // simple
  109. $collection->add('baz', new Route(
  110. '/test/baz'
  111. ));
  112. // simple with extension
  113. $collection->add('baz2', new Route(
  114. '/test/baz.html'
  115. ));
  116. // trailing slash
  117. $collection->add('baz3', new Route(
  118. '/test/baz3/'
  119. ));
  120. // trailing slash with variable
  121. $collection->add('baz4', new Route(
  122. '/test/{foo}/'
  123. ));
  124. // trailing slash and method
  125. $collection->add('baz5', new Route(
  126. '/test/{foo}/',
  127. array(),
  128. array(),
  129. array(),
  130. '',
  131. array(),
  132. array('post')
  133. ));
  134. // complex name
  135. $collection->add('baz.baz6', new Route(
  136. '/test/{foo}/',
  137. array(),
  138. array(),
  139. array(),
  140. '',
  141. array(),
  142. array('put')
  143. ));
  144. // defaults without variable
  145. $collection->add('foofoo', new Route(
  146. '/foofoo',
  147. array('def' => 'test')
  148. ));
  149. // pattern with quotes
  150. $collection->add('quoter', new Route(
  151. '/{quoter}',
  152. array(),
  153. array('quoter' => '[\']+')
  154. ));
  155. // space in pattern
  156. $collection->add('space', new Route(
  157. '/spa ce'
  158. ));
  159. // prefixes
  160. $collection1 = new RouteCollection();
  161. $collection1->add('overridden', new Route('/overridden1'));
  162. $collection1->add('foo1', new Route('/{foo}'));
  163. $collection1->add('bar1', new Route('/{bar}'));
  164. $collection1->addPrefix('/b\'b');
  165. $collection2 = new RouteCollection();
  166. $collection2->addCollection($collection1);
  167. $collection2->add('overridden', new Route('/{var}', array(), array('var' => '.*')));
  168. $collection1 = new RouteCollection();
  169. $collection1->add('foo2', new Route('/{foo1}'));
  170. $collection1->add('bar2', new Route('/{bar1}'));
  171. $collection1->addPrefix('/b\'b');
  172. $collection2->addCollection($collection1);
  173. $collection2->addPrefix('/a');
  174. $collection->addCollection($collection2);
  175. // overridden through addCollection() and multiple sub-collections with no own prefix
  176. $collection1 = new RouteCollection();
  177. $collection1->add('overridden2', new Route('/old'));
  178. $collection1->add('helloWorld', new Route('/hello/{who}', array('who' => 'World!')));
  179. $collection2 = new RouteCollection();
  180. $collection3 = new RouteCollection();
  181. $collection3->add('overridden2', new Route('/new'));
  182. $collection3->add('hey', new Route('/hey/'));
  183. $collection2->addCollection($collection3);
  184. $collection1->addCollection($collection2);
  185. $collection1->addPrefix('/multi');
  186. $collection->addCollection($collection1);
  187. // "dynamic" prefix
  188. $collection1 = new RouteCollection();
  189. $collection1->add('foo3', new Route('/{foo}'));
  190. $collection1->add('bar3', new Route('/{bar}'));
  191. $collection1->addPrefix('/b');
  192. $collection1->addPrefix('{_locale}');
  193. $collection->addCollection($collection1);
  194. // route between collections
  195. $collection->add('ababa', new Route('/ababa'));
  196. // collection with static prefix but only one route
  197. $collection1 = new RouteCollection();
  198. $collection1->add('foo4', new Route('/{foo}'));
  199. $collection1->addPrefix('/aba');
  200. $collection->addCollection($collection1);
  201. // prefix and host
  202. $collection1 = new RouteCollection();
  203. $route1 = new Route('/route1', array(), array(), array(), 'a.example.com');
  204. $collection1->add('route1', $route1);
  205. $route2 = new Route('/c2/route2', array(), array(), array(), 'a.example.com');
  206. $collection1->add('route2', $route2);
  207. $route3 = new Route('/c2/route3', array(), array(), array(), 'b.example.com');
  208. $collection1->add('route3', $route3);
  209. $route4 = new Route('/route4', array(), array(), array(), 'a.example.com');
  210. $collection1->add('route4', $route4);
  211. $route5 = new Route('/route5', array(), array(), array(), 'c.example.com');
  212. $collection1->add('route5', $route5);
  213. $route6 = new Route('/route6', array(), array(), array(), null);
  214. $collection1->add('route6', $route6);
  215. $collection->addCollection($collection1);
  216. // host and variables
  217. $collection1 = new RouteCollection();
  218. $route11 = new Route('/route11', array(), array(), array(), '{var1}.example.com');
  219. $collection1->add('route11', $route11);
  220. $route12 = new Route('/route12', array('var1' => 'val'), array(), array(), '{var1}.example.com');
  221. $collection1->add('route12', $route12);
  222. $route13 = new Route('/route13/{name}', array(), array(), array(), '{var1}.example.com');
  223. $collection1->add('route13', $route13);
  224. $route14 = new Route('/route14/{name}', array('var1' => 'val'), array(), array(), '{var1}.example.com');
  225. $collection1->add('route14', $route14);
  226. $route15 = new Route('/route15/{name}', array(), array(), array(), 'c.example.com');
  227. $collection1->add('route15', $route15);
  228. $route16 = new Route('/route16/{name}', array('var1' => 'val'), array(), array(), null);
  229. $collection1->add('route16', $route16);
  230. $route17 = new Route('/route17', array(), array(), array(), null);
  231. $collection1->add('route17', $route17);
  232. $collection->addCollection($collection1);
  233. // multiple sub-collections with a single route and a prefix each
  234. $collection1 = new RouteCollection();
  235. $collection1->add('a', new Route('/a...'));
  236. $collection2 = new RouteCollection();
  237. $collection2->add('b', new Route('/{var}'));
  238. $collection3 = new RouteCollection();
  239. $collection3->add('c', new Route('/{var}'));
  240. $collection3->addPrefix('/c');
  241. $collection2->addCollection($collection3);
  242. $collection2->addPrefix('/b');
  243. $collection1->addCollection($collection2);
  244. $collection1->addPrefix('/a');
  245. $collection->addCollection($collection1);
  246. /* test case 2 */
  247. $redirectCollection = clone $collection;
  248. // force HTTPS redirection
  249. $redirectCollection->add('secure', new Route(
  250. '/secure',
  251. array(),
  252. array(),
  253. array(),
  254. '',
  255. array('https')
  256. ));
  257. // force HTTP redirection
  258. $redirectCollection->add('nonsecure', new Route(
  259. '/nonsecure',
  260. array(),
  261. array(),
  262. array(),
  263. '',
  264. array('http')
  265. ));
  266. /* test case 3 */
  267. $rootprefixCollection = new RouteCollection();
  268. $rootprefixCollection->add('static', new Route('/test'));
  269. $rootprefixCollection->add('dynamic', new Route('/{var}'));
  270. $rootprefixCollection->addPrefix('rootprefix');
  271. $route = new Route('/with-condition');
  272. $route->setCondition('context.getMethod() == "GET"');
  273. $rootprefixCollection->add('with-condition', $route);
  274. return array(
  275. array($collection, 'url_matcher1.php', array()),
  276. array($redirectCollection, 'url_matcher2.php', array('base_class' => 'Symfony\Component\Routing\Tests\Fixtures\RedirectableUrlMatcher')),
  277. array($rootprefixCollection, 'url_matcher3.php', array()),
  278. );
  279. }
  280. private function generateDumpedMatcher(RouteCollection $collection, $redirectableStub = false)
  281. {
  282. $options = array('class' => $this->matcherClass);
  283. if ($redirectableStub) {
  284. $options['base_class'] = '\Symfony\Component\Routing\Tests\Matcher\Dumper\RedirectableUrlMatcherStub';
  285. }
  286. $dumper = new PhpMatcherDumper($collection);
  287. $code = $dumper->dump($options);
  288. file_put_contents($this->dumpPath, $code);
  289. include $this->dumpPath;
  290. return $this->matcherClass;
  291. }
  292. }
  293. abstract class RedirectableUrlMatcherStub extends UrlMatcher implements RedirectableUrlMatcherInterface
  294. {
  295. public function redirect($path, $route, $scheme = null)
  296. {
  297. }
  298. }