DependencyInjection/RoutingResolverPassTest.php000064400000002254150312232120016030 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\DependencyInjection; use PHPUnit\Framework\TestCase; use Symfony\Component\Config\Loader\LoaderResolver; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\Routing\DependencyInjection\RoutingResolverPass; class RoutingResolverPassTest extends TestCase { public function testProcess() { $container = new ContainerBuilder(); $container->register('routing.resolver', LoaderResolver::class); $container->register('loader1')->addTag('routing.loader'); $container->register('loader2')->addTag('routing.loader'); (new RoutingResolverPass())->process($container); $this->assertEquals( [['addLoader', [new Reference('loader1')]], ['addLoader', [new Reference('loader2')]]], $container->getDefinition('routing.resolver')->getMethodCalls() ); } } RouteTest.php000064400000032111150312232120007200 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests; use PHPUnit\Framework\TestCase; use Symfony\Component\Routing\Route; class RouteTest extends TestCase { public function testConstructor() { $route = new Route('/{foo}', ['foo' => 'bar'], ['foo' => '\d+'], ['foo' => 'bar'], '{locale}.example.com'); $this->assertEquals('/{foo}', $route->getPath(), '__construct() takes a path as its first argument'); $this->assertEquals(['foo' => 'bar'], $route->getDefaults(), '__construct() takes defaults as its second argument'); $this->assertEquals(['foo' => '\d+'], $route->getRequirements(), '__construct() takes requirements as its third argument'); $this->assertEquals('bar', $route->getOption('foo'), '__construct() takes options as its fourth argument'); $this->assertEquals('{locale}.example.com', $route->getHost(), '__construct() takes a host pattern as its fifth argument'); $route = new Route('/', [], [], [], '', ['Https'], ['POST', 'put'], 'context.getMethod() == "GET"'); $this->assertEquals(['https'], $route->getSchemes(), '__construct() takes schemes as its sixth argument and lowercases it'); $this->assertEquals(['POST', 'PUT'], $route->getMethods(), '__construct() takes methods as its seventh argument and uppercases it'); $this->assertEquals('context.getMethod() == "GET"', $route->getCondition(), '__construct() takes a condition as its eight argument'); $route = new Route('/', [], [], [], '', 'Https', 'Post'); $this->assertEquals(['https'], $route->getSchemes(), '__construct() takes a single scheme as its sixth argument'); $this->assertEquals(['POST'], $route->getMethods(), '__construct() takes a single method as its seventh argument'); } public function testPath() { $route = new Route('/{foo}'); $route->setPath('/{bar}'); $this->assertEquals('/{bar}', $route->getPath(), '->setPath() sets the path'); $route->setPath(''); $this->assertEquals('/', $route->getPath(), '->setPath() adds a / at the beginning of the path if needed'); $route->setPath('bar'); $this->assertEquals('/bar', $route->getPath(), '->setPath() adds a / at the beginning of the path if needed'); $this->assertEquals($route, $route->setPath(''), '->setPath() implements a fluent interface'); $route->setPath('//path'); $this->assertEquals('/path', $route->getPath(), '->setPath() does not allow two slashes "//" at the beginning of the path as it would be confused with a network path when generating the path from the route'); } public function testOptions() { $route = new Route('/{foo}'); $route->setOptions(['foo' => 'bar']); $this->assertEquals(array_merge([ 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler', ], ['foo' => 'bar']), $route->getOptions(), '->setOptions() sets the options'); $this->assertEquals($route, $route->setOptions([]), '->setOptions() implements a fluent interface'); $route->setOptions(['foo' => 'foo']); $route->addOptions(['bar' => 'bar']); $this->assertEquals($route, $route->addOptions([]), '->addOptions() implements a fluent interface'); $this->assertEquals(['foo' => 'foo', 'bar' => 'bar', 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler'], $route->getOptions(), '->addDefaults() keep previous defaults'); } public function testOption() { $route = new Route('/{foo}'); $this->assertFalse($route->hasOption('foo'), '->hasOption() return false if option is not set'); $this->assertEquals($route, $route->setOption('foo', 'bar'), '->setOption() implements a fluent interface'); $this->assertEquals('bar', $route->getOption('foo'), '->setOption() sets the option'); $this->assertTrue($route->hasOption('foo'), '->hasOption() return true if option is set'); } public function testDefaults() { $route = new Route('/{foo}'); $route->setDefaults(['foo' => 'bar']); $this->assertEquals(['foo' => 'bar'], $route->getDefaults(), '->setDefaults() sets the defaults'); $this->assertEquals($route, $route->setDefaults([]), '->setDefaults() implements a fluent interface'); $route->setDefault('foo', 'bar'); $this->assertEquals('bar', $route->getDefault('foo'), '->setDefault() sets a default value'); $route->setDefault('foo2', 'bar2'); $this->assertEquals('bar2', $route->getDefault('foo2'), '->getDefault() return the default value'); $this->assertNull($route->getDefault('not_defined'), '->getDefault() return null if default value is not set'); $route->setDefault('_controller', $closure = function () { return 'Hello'; }); $this->assertEquals($closure, $route->getDefault('_controller'), '->setDefault() sets a default value'); $route->setDefaults(['foo' => 'foo']); $route->addDefaults(['bar' => 'bar']); $this->assertEquals($route, $route->addDefaults([]), '->addDefaults() implements a fluent interface'); $this->assertEquals(['foo' => 'foo', 'bar' => 'bar'], $route->getDefaults(), '->addDefaults() keep previous defaults'); } public function testRequirements() { $route = new Route('/{foo}'); $route->setRequirements(['foo' => '\d+']); $this->assertEquals(['foo' => '\d+'], $route->getRequirements(), '->setRequirements() sets the requirements'); $this->assertEquals('\d+', $route->getRequirement('foo'), '->getRequirement() returns a requirement'); $this->assertNull($route->getRequirement('bar'), '->getRequirement() returns null if a requirement is not defined'); $route->setRequirements(['foo' => '^\d+$']); $this->assertEquals('\d+', $route->getRequirement('foo'), '->getRequirement() removes ^ and $ from the path'); $this->assertEquals($route, $route->setRequirements([]), '->setRequirements() implements a fluent interface'); $route->setRequirements(['foo' => '\d+']); $route->addRequirements(['bar' => '\d+']); $this->assertEquals($route, $route->addRequirements([]), '->addRequirements() implements a fluent interface'); $this->assertEquals(['foo' => '\d+', 'bar' => '\d+'], $route->getRequirements(), '->addRequirement() keep previous requirements'); } public function testRequirement() { $route = new Route('/{foo}'); $this->assertFalse($route->hasRequirement('foo'), '->hasRequirement() return false if requirement is not set'); $route->setRequirement('foo', '^\d+$'); $this->assertEquals('\d+', $route->getRequirement('foo'), '->setRequirement() removes ^ and $ from the path'); $this->assertTrue($route->hasRequirement('foo'), '->hasRequirement() return true if requirement is set'); } /** * @dataProvider getInvalidRequirements */ public function testSetInvalidRequirement($req) { $this->expectException('InvalidArgumentException'); $route = new Route('/{foo}'); $route->setRequirement('foo', $req); } public function getInvalidRequirements() { return [ [''], [[]], ['^$'], ['^'], ['$'], ]; } public function testHost() { $route = new Route('/'); $route->setHost('{locale}.example.net'); $this->assertEquals('{locale}.example.net', $route->getHost(), '->setHost() sets the host pattern'); } public function testScheme() { $route = new Route('/'); $this->assertEquals([], $route->getSchemes(), 'schemes is initialized with []'); $this->assertFalse($route->hasScheme('http')); $route->setSchemes('hTTp'); $this->assertEquals(['http'], $route->getSchemes(), '->setSchemes() accepts a single scheme string and lowercases it'); $this->assertTrue($route->hasScheme('htTp')); $this->assertFalse($route->hasScheme('httpS')); $route->setSchemes(['HttpS', 'hTTp']); $this->assertEquals(['https', 'http'], $route->getSchemes(), '->setSchemes() accepts an array of schemes and lowercases them'); $this->assertTrue($route->hasScheme('htTp')); $this->assertTrue($route->hasScheme('httpS')); } public function testMethod() { $route = new Route('/'); $this->assertEquals([], $route->getMethods(), 'methods is initialized with []'); $route->setMethods('gEt'); $this->assertEquals(['GET'], $route->getMethods(), '->setMethods() accepts a single method string and uppercases it'); $route->setMethods(['gEt', 'PosT']); $this->assertEquals(['GET', 'POST'], $route->getMethods(), '->setMethods() accepts an array of methods and uppercases them'); } public function testCondition() { $route = new Route('/'); $this->assertSame('', $route->getCondition()); $route->setCondition('context.getMethod() == "GET"'); $this->assertSame('context.getMethod() == "GET"', $route->getCondition()); } public function testCompile() { $route = new Route('/{foo}'); $this->assertInstanceOf('Symfony\Component\Routing\CompiledRoute', $compiled = $route->compile(), '->compile() returns a compiled route'); $this->assertSame($compiled, $route->compile(), '->compile() only compiled the route once if unchanged'); $route->setRequirement('foo', '.*'); $this->assertNotSame($compiled, $route->compile(), '->compile() recompiles if the route was modified'); } public function testSerialize() { $route = new Route('/prefix/{foo}', ['foo' => 'default'], ['foo' => '\d+']); $serialized = serialize($route); $unserialized = unserialize($serialized); $this->assertEquals($route, $unserialized); $this->assertNotSame($route, $unserialized); } /** * Tests that the compiled version is also serialized to prevent the overhead * of compiling it again after unserialize. */ public function testSerializeWhenCompiled() { $route = new Route('/prefix/{foo}', ['foo' => 'default'], ['foo' => '\d+']); $route->setHost('{locale}.example.net'); $route->compile(); $serialized = serialize($route); $unserialized = unserialize($serialized); $this->assertEquals($route, $unserialized); $this->assertNotSame($route, $unserialized); } /** * Tests that unserialization does not fail when the compiled Route is of a * class other than CompiledRoute, such as a subclass of it. */ public function testSerializeWhenCompiledWithClass() { $route = new Route('/', [], [], ['compiler_class' => '\Symfony\Component\Routing\Tests\Fixtures\CustomRouteCompiler']); $this->assertInstanceOf('\Symfony\Component\Routing\Tests\Fixtures\CustomCompiledRoute', $route->compile(), '->compile() returned a proper route'); $serialized = serialize($route); try { $unserialized = unserialize($serialized); $this->assertInstanceOf('\Symfony\Component\Routing\Tests\Fixtures\CustomCompiledRoute', $unserialized->compile(), 'the unserialized route compiled successfully'); } catch (\Exception $e) { $this->fail('unserializing a route which uses a custom compiled route class'); } } /** * Tests that the serialized representation of a route in one symfony version * also works in later symfony versions, i.e. the unserialized route is in the * same state as another, semantically equivalent, route. */ public function testSerializedRepresentationKeepsWorking() { $serialized = 'C:31:"Symfony\Component\Routing\Route":936:{a:8:{s:4:"path";s:13:"/prefix/{foo}";s:4:"host";s:20:"{locale}.example.net";s:8:"defaults";a:1:{s:3:"foo";s:7:"default";}s:12:"requirements";a:1:{s:3:"foo";s:3:"\d+";}s:7:"options";a:1:{s:14:"compiler_class";s:39:"Symfony\Component\Routing\RouteCompiler";}s:7:"schemes";a:0:{}s:7:"methods";a:0:{}s:8:"compiled";C:39:"Symfony\Component\Routing\CompiledRoute":571:{a:8:{s:4:"vars";a:2:{i:0;s:6:"locale";i:1;s:3:"foo";}s:11:"path_prefix";s:7:"/prefix";s:10:"path_regex";s:31:"#^/prefix(?:/(?P\d+))?$#sD";s:11:"path_tokens";a:2:{i:0;a:4:{i:0;s:8:"variable";i:1;s:1:"/";i:2;s:3:"\d+";i:3;s:3:"foo";}i:1;a:2:{i:0;s:4:"text";i:1;s:7:"/prefix";}}s:9:"path_vars";a:1:{i:0;s:3:"foo";}s:10:"host_regex";s:40:"#^(?P[^\.]++)\.example\.net$#sDi";s:11:"host_tokens";a:2:{i:0;a:2:{i:0;s:4:"text";i:1;s:12:".example.net";}i:1;a:4:{i:0;s:8:"variable";i:1;s:0:"";i:2;s:7:"[^\.]++";i:3;s:6:"locale";}}s:9:"host_vars";a:1:{i:0;s:6:"locale";}}}}}'; $unserialized = unserialize($serialized); $route = new Route('/prefix/{foo}', ['foo' => 'default'], ['foo' => '\d+']); $route->setHost('{locale}.example.net'); $route->compile(); $this->assertEquals($route, $unserialized); $this->assertNotSame($route, $unserialized); } } RequestContextTest.php000064400000012766150312232120011115 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\RequestContext; class RequestContextTest extends TestCase { public function testConstruct() { $requestContext = new RequestContext( 'foo', 'post', 'foo.bar', 'HTTPS', 8080, 444, '/baz', 'bar=foobar' ); $this->assertEquals('foo', $requestContext->getBaseUrl()); $this->assertEquals('POST', $requestContext->getMethod()); $this->assertEquals('foo.bar', $requestContext->getHost()); $this->assertEquals('https', $requestContext->getScheme()); $this->assertSame(8080, $requestContext->getHttpPort()); $this->assertSame(444, $requestContext->getHttpsPort()); $this->assertEquals('/baz', $requestContext->getPathInfo()); $this->assertEquals('bar=foobar', $requestContext->getQueryString()); } public function testFromRequest() { $request = Request::create('https://test.com:444/foo?bar=baz'); $requestContext = new RequestContext(); $requestContext->setHttpPort(123); $requestContext->fromRequest($request); $this->assertEquals('', $requestContext->getBaseUrl()); $this->assertEquals('GET', $requestContext->getMethod()); $this->assertEquals('test.com', $requestContext->getHost()); $this->assertEquals('https', $requestContext->getScheme()); $this->assertEquals('/foo', $requestContext->getPathInfo()); $this->assertEquals('bar=baz', $requestContext->getQueryString()); $this->assertSame(123, $requestContext->getHttpPort()); $this->assertSame(444, $requestContext->getHttpsPort()); $request = Request::create('http://test.com:8080/foo?bar=baz'); $requestContext = new RequestContext(); $requestContext->setHttpsPort(567); $requestContext->fromRequest($request); $this->assertSame(8080, $requestContext->getHttpPort()); $this->assertSame(567, $requestContext->getHttpsPort()); } public function testGetParameters() { $requestContext = new RequestContext(); $this->assertEquals([], $requestContext->getParameters()); $requestContext->setParameters(['foo' => 'bar']); $this->assertEquals(['foo' => 'bar'], $requestContext->getParameters()); } public function testHasParameter() { $requestContext = new RequestContext(); $requestContext->setParameters(['foo' => 'bar']); $this->assertTrue($requestContext->hasParameter('foo')); $this->assertFalse($requestContext->hasParameter('baz')); } public function testGetParameter() { $requestContext = new RequestContext(); $requestContext->setParameters(['foo' => 'bar']); $this->assertEquals('bar', $requestContext->getParameter('foo')); $this->assertNull($requestContext->getParameter('baz')); } public function testSetParameter() { $requestContext = new RequestContext(); $requestContext->setParameter('foo', 'bar'); $this->assertEquals('bar', $requestContext->getParameter('foo')); } public function testMethod() { $requestContext = new RequestContext(); $requestContext->setMethod('post'); $this->assertSame('POST', $requestContext->getMethod()); } public function testScheme() { $requestContext = new RequestContext(); $requestContext->setScheme('HTTPS'); $this->assertSame('https', $requestContext->getScheme()); } public function testHost() { $requestContext = new RequestContext(); $requestContext->setHost('eXampLe.com'); $this->assertSame('example.com', $requestContext->getHost()); } public function testQueryString() { $requestContext = new RequestContext(); $requestContext->setQueryString(null); $this->assertSame('', $requestContext->getQueryString()); } public function testPort() { $requestContext = new RequestContext(); $requestContext->setHttpPort('123'); $requestContext->setHttpsPort('456'); $this->assertSame(123, $requestContext->getHttpPort()); $this->assertSame(456, $requestContext->getHttpsPort()); } public function testFluentInterface() { $requestContext = new RequestContext(); $this->assertSame($requestContext, $requestContext->setBaseUrl('/app.php')); $this->assertSame($requestContext, $requestContext->setPathInfo('/index')); $this->assertSame($requestContext, $requestContext->setMethod('POST')); $this->assertSame($requestContext, $requestContext->setScheme('https')); $this->assertSame($requestContext, $requestContext->setHost('example.com')); $this->assertSame($requestContext, $requestContext->setQueryString('foo=bar')); $this->assertSame($requestContext, $requestContext->setHttpPort(80)); $this->assertSame($requestContext, $requestContext->setHttpsPort(443)); $this->assertSame($requestContext, $requestContext->setParameters([])); $this->assertSame($requestContext, $requestContext->setParameter('foo', 'bar')); } } RouteCompilerTest.php000064400000033145150312232120010703 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests; use PHPUnit\Framework\TestCase; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCompiler; class RouteCompilerTest extends TestCase { /** * @dataProvider provideCompileData */ public function testCompile($name, $arguments, $prefix, $regex, $variables, $tokens) { $r = new \ReflectionClass('Symfony\\Component\\Routing\\Route'); $route = $r->newInstanceArgs($arguments); $compiled = $route->compile(); $this->assertEquals($prefix, $compiled->getStaticPrefix(), $name.' (static prefix)'); $this->assertEquals($regex, $compiled->getRegex(), $name.' (regex)'); $this->assertEquals($variables, $compiled->getVariables(), $name.' (variables)'); $this->assertEquals($tokens, $compiled->getTokens(), $name.' (tokens)'); } public function provideCompileData() { return [ [ 'Static route', ['/foo'], '/foo', '#^/foo$#sD', [], [ ['text', '/foo'], ], ], [ 'Route with a variable', ['/foo/{bar}'], '/foo', '#^/foo/(?P[^/]++)$#sD', ['bar'], [ ['variable', '/', '[^/]++', 'bar'], ['text', '/foo'], ], ], [ 'Route with a variable that has a default value', ['/foo/{bar}', ['bar' => 'bar']], '/foo', '#^/foo(?:/(?P[^/]++))?$#sD', ['bar'], [ ['variable', '/', '[^/]++', 'bar'], ['text', '/foo'], ], ], [ 'Route with several variables', ['/foo/{bar}/{foobar}'], '/foo', '#^/foo/(?P[^/]++)/(?P[^/]++)$#sD', ['bar', 'foobar'], [ ['variable', '/', '[^/]++', 'foobar'], ['variable', '/', '[^/]++', 'bar'], ['text', '/foo'], ], ], [ 'Route with several variables that have default values', ['/foo/{bar}/{foobar}', ['bar' => 'bar', 'foobar' => '']], '/foo', '#^/foo(?:/(?P[^/]++)(?:/(?P[^/]++))?)?$#sD', ['bar', 'foobar'], [ ['variable', '/', '[^/]++', 'foobar'], ['variable', '/', '[^/]++', 'bar'], ['text', '/foo'], ], ], [ 'Route with several variables but some of them have no default values', ['/foo/{bar}/{foobar}', ['bar' => 'bar']], '/foo', '#^/foo/(?P[^/]++)/(?P[^/]++)$#sD', ['bar', 'foobar'], [ ['variable', '/', '[^/]++', 'foobar'], ['variable', '/', '[^/]++', 'bar'], ['text', '/foo'], ], ], [ 'Route with an optional variable as the first segment', ['/{bar}', ['bar' => 'bar']], '', '#^/(?P[^/]++)?$#sD', ['bar'], [ ['variable', '/', '[^/]++', 'bar'], ], ], [ 'Route with a requirement of 0', ['/{bar}', ['bar' => null], ['bar' => '0']], '', '#^/(?P0)?$#sD', ['bar'], [ ['variable', '/', '0', 'bar'], ], ], [ 'Route with an optional variable as the first segment with requirements', ['/{bar}', ['bar' => 'bar'], ['bar' => '(foo|bar)']], '', '#^/(?P(foo|bar))?$#sD', ['bar'], [ ['variable', '/', '(foo|bar)', 'bar'], ], ], [ 'Route with only optional variables', ['/{foo}/{bar}', ['foo' => 'foo', 'bar' => 'bar']], '', '#^/(?P[^/]++)?(?:/(?P[^/]++))?$#sD', ['foo', 'bar'], [ ['variable', '/', '[^/]++', 'bar'], ['variable', '/', '[^/]++', 'foo'], ], ], [ 'Route with a variable in last position', ['/foo-{bar}'], '/foo-', '#^/foo\-(?P[^/]++)$#sD', ['bar'], [ ['variable', '-', '[^/]++', 'bar'], ['text', '/foo'], ], ], [ 'Route with nested placeholders', ['/{static{var}static}'], '/{static', '#^/\{static(?P[^/]+)static\}$#sD', ['var'], [ ['text', 'static}'], ['variable', '', '[^/]+', 'var'], ['text', '/{static'], ], ], [ 'Route without separator between variables', ['/{w}{x}{y}{z}.{_format}', ['z' => 'default-z', '_format' => 'html'], ['y' => '(y|Y)']], '', '#^/(?P[^/\.]+)(?P[^/\.]+)(?P(y|Y))(?:(?P[^/\.]++)(?:\.(?P<_format>[^/]++))?)?$#sD', ['w', 'x', 'y', 'z', '_format'], [ ['variable', '.', '[^/]++', '_format'], ['variable', '', '[^/\.]++', 'z'], ['variable', '', '(y|Y)', 'y'], ['variable', '', '[^/\.]+', 'x'], ['variable', '/', '[^/\.]+', 'w'], ], ], [ 'Route with a format', ['/foo/{bar}.{_format}'], '/foo', '#^/foo/(?P[^/\.]++)\.(?P<_format>[^/]++)$#sD', ['bar', '_format'], [ ['variable', '.', '[^/]++', '_format'], ['variable', '/', '[^/\.]++', 'bar'], ['text', '/foo'], ], ], [ 'Static non UTF-8 route', ["/fo\xE9"], "/fo\xE9", "#^/fo\xE9$#sD", [], [ ['text', "/fo\xE9"], ], ], [ 'Route with an explicit UTF-8 requirement', ['/{bar}', ['bar' => null], ['bar' => '.'], ['utf8' => true]], '', '#^/(?P.)?$#sDu', ['bar'], [ ['variable', '/', '.', 'bar', true], ], ], ]; } /** * @group legacy * @dataProvider provideCompileImplicitUtf8Data * @expectedDeprecation Using UTF-8 route %s without setting the "utf8" option is deprecated %s. */ public function testCompileImplicitUtf8Data($name, $arguments, $prefix, $regex, $variables, $tokens, $deprecationType) { $r = new \ReflectionClass('Symfony\\Component\\Routing\\Route'); $route = $r->newInstanceArgs($arguments); $compiled = $route->compile(); $this->assertEquals($prefix, $compiled->getStaticPrefix(), $name.' (static prefix)'); $this->assertEquals($regex, $compiled->getRegex(), $name.' (regex)'); $this->assertEquals($variables, $compiled->getVariables(), $name.' (variables)'); $this->assertEquals($tokens, $compiled->getTokens(), $name.' (tokens)'); } public function provideCompileImplicitUtf8Data() { return [ [ 'Static UTF-8 route', ['/foé'], '/foé', '#^/foé$#sDu', [], [ ['text', '/foé'], ], 'patterns', ], [ 'Route with an implicit UTF-8 requirement', ['/{bar}', ['bar' => null], ['bar' => 'é']], '', '#^/(?Pé)?$#sDu', ['bar'], [ ['variable', '/', 'é', 'bar', true], ], 'requirements', ], [ 'Route with a UTF-8 class requirement', ['/{bar}', ['bar' => null], ['bar' => '\pM']], '', '#^/(?P\pM)?$#sDu', ['bar'], [ ['variable', '/', '\pM', 'bar', true], ], 'requirements', ], [ 'Route with a UTF-8 separator', ['/foo/{bar}§{_format}', [], [], ['compiler_class' => Utf8RouteCompiler::class]], '/foo', '#^/foo/(?P[^/§]++)§(?P<_format>[^/]++)$#sDu', ['bar', '_format'], [ ['variable', '§', '[^/]++', '_format', true], ['variable', '/', '[^/§]++', 'bar', true], ['text', '/foo'], ], 'patterns', ], ]; } public function testRouteWithSameVariableTwice() { $this->expectException('LogicException'); $route = new Route('/{name}/{name}'); $route->compile(); } public function testRouteCharsetMismatch() { $this->expectException('LogicException'); $route = new Route("/\xE9/{bar}", [], ['bar' => '.'], ['utf8' => true]); $route->compile(); } public function testRequirementCharsetMismatch() { $this->expectException('LogicException'); $route = new Route('/foo/{bar}', [], ['bar' => "\xE9"], ['utf8' => true]); $route->compile(); } public function testRouteWithFragmentAsPathParameter() { $this->expectException('InvalidArgumentException'); $route = new Route('/{_fragment}'); $route->compile(); } /** * @dataProvider getVariableNamesStartingWithADigit */ public function testRouteWithVariableNameStartingWithADigit($name) { $this->expectException('DomainException'); $route = new Route('/{'.$name.'}'); $route->compile(); } public function getVariableNamesStartingWithADigit() { return [ ['09'], ['123'], ['1e2'], ]; } /** * @dataProvider provideCompileWithHostData */ public function testCompileWithHost($name, $arguments, $prefix, $regex, $variables, $pathVariables, $tokens, $hostRegex, $hostVariables, $hostTokens) { $r = new \ReflectionClass('Symfony\\Component\\Routing\\Route'); $route = $r->newInstanceArgs($arguments); $compiled = $route->compile(); $this->assertEquals($prefix, $compiled->getStaticPrefix(), $name.' (static prefix)'); $this->assertEquals($regex, str_replace(["\n", ' '], '', $compiled->getRegex()), $name.' (regex)'); $this->assertEquals($variables, $compiled->getVariables(), $name.' (variables)'); $this->assertEquals($pathVariables, $compiled->getPathVariables(), $name.' (path variables)'); $this->assertEquals($tokens, $compiled->getTokens(), $name.' (tokens)'); $this->assertEquals($hostRegex, str_replace(["\n", ' '], '', $compiled->getHostRegex()), $name.' (host regex)'); $this->assertEquals($hostVariables, $compiled->getHostVariables(), $name.' (host variables)'); $this->assertEquals($hostTokens, $compiled->getHostTokens(), $name.' (host tokens)'); } public function provideCompileWithHostData() { return [ [ 'Route with host pattern', ['/hello', [], [], [], 'www.example.com'], '/hello', '#^/hello$#sD', [], [], [ ['text', '/hello'], ], '#^www\.example\.com$#sDi', [], [ ['text', 'www.example.com'], ], ], [ 'Route with host pattern and some variables', ['/hello/{name}', [], [], [], 'www.example.{tld}'], '/hello', '#^/hello/(?P[^/]++)$#sD', ['tld', 'name'], ['name'], [ ['variable', '/', '[^/]++', 'name'], ['text', '/hello'], ], '#^www\.example\.(?P[^\.]++)$#sDi', ['tld'], [ ['variable', '.', '[^\.]++', 'tld'], ['text', 'www.example'], ], ], [ 'Route with variable at beginning of host', ['/hello', [], [], [], '{locale}.example.{tld}'], '/hello', '#^/hello$#sD', ['locale', 'tld'], [], [ ['text', '/hello'], ], '#^(?P[^\.]++)\.example\.(?P[^\.]++)$#sDi', ['locale', 'tld'], [ ['variable', '.', '[^\.]++', 'tld'], ['text', '.example'], ['variable', '', '[^\.]++', 'locale'], ], ], [ 'Route with host variables that has a default value', ['/hello', ['locale' => 'a', 'tld' => 'b'], [], [], '{locale}.example.{tld}'], '/hello', '#^/hello$#sD', ['locale', 'tld'], [], [ ['text', '/hello'], ], '#^(?P[^\.]++)\.example\.(?P[^\.]++)$#sDi', ['locale', 'tld'], [ ['variable', '.', '[^\.]++', 'tld'], ['text', '.example'], ['variable', '', '[^\.]++', 'locale'], ], ], ]; } public function testRouteWithTooLongVariableName() { $this->expectException('DomainException'); $route = new Route(sprintf('/{%s}', str_repeat('a', RouteCompiler::VARIABLE_MAXIMUM_LENGTH + 1))); $route->compile(); } } class Utf8RouteCompiler extends RouteCompiler { const SEPARATORS = '/§'; } Fixtures/localized/utf8.xml000064400000000736150312232120011730 0ustar00 Fixtures/map_defaults.xml000064400000001302150312232120011526 0ustar00 AcmeBlogBundle:Blog:index true 1 3.5 foo Fixtures/with_define_path_variable.php000064400000000123150312232120014217 0ustar00import('validpattern.php'); $collection->addDefaults([ 'foo' => 123, ]); $collection->addRequirements([ 'foo' => '\d+', ]); $collection->addOptions([ 'foo' => 'bar', ]); $collection->setCondition('context.getMethod() == "POST"'); $collection->addPrefix('/prefix'); return $collection; Fixtures/foo1.xml000064400000000000150312232120007720 0ustar00Fixtures/bar.xml000064400000000000150312232120007620 0ustar00Fixtures/OtherAnnotatedClasses/VariadicClass.php000064400000000611150312232120016020 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Fixtures\OtherAnnotatedClasses; class VariadicClass { public function routeAction(...$params) { } } Fixtures/OtherAnnotatedClasses/NoStartTagClass.php000064400000000032150312232120016321 0ustar00class NoStartTagClass { } Fixtures/OtherAnnotatedClasses/AnonymousClassInTrait.php000064400000000746150312232120017572 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Fixtures\OtherAnnotatedClasses; trait AnonymousClassInTrait { public function test() { return new class() { public function foo() { } }; } } Fixtures/withdoctype.xml000064400000000061150312232120011426 0ustar00 Fixtures/AnnotatedClasses/BarClass.php000064400000000654150312232120014007 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses; class BarClass { public function routeAction($arg1, $arg2 = 'defaultValue2', $arg3 = 'defaultValue3') { } } Fixtures/AnnotatedClasses/BazClass.php000064400000000562150312232120014015 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses; class BazClass { public function __invoke() { } } Fixtures/AnnotatedClasses/EncodingClass.php000064400000000224150312232120015022 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses; abstract class AbstractClass { abstract public function abstractRouteAction(); public function routeAction($arg1, $arg2 = 'defaultValue2', $arg3 = 'defaultValue3') { } } Fixtures/AnnotatedClasses/FooTrait.php000064400000000273150312232120014041 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses; class FooClass { } Fixtures/incomplete.yml000064400000000102150312232120011217 0ustar00blog_show: defaults: { _controller: MyBlogBundle:Blog:show } Fixtures/map_in_map_defaults.xml000064400000001411150312232120013052 0ustar00 AcmeBlogBundle:Blog:index true 1 3.5 foo Fixtures/php_dsl.php000064400000001040150312232120010501 0ustar00collection() ->add('foo', '/foo') ->condition('abc') ->options(['utf8' => true]) ->add('buz', 'zub') ->controller('foo:act'); $routes->import('php_dsl_sub.php') ->prefix('/sub') ->requirements(['id' => '\d+']); $routes->add('ouf', '/ouf') ->schemes(['https']) ->methods(['GET']) ->defaults(['id' => 0]); }; Fixtures/missing_id.xml000064400000000460150312232120011213 0ustar00 Fixtures/list_null_values.xml000064400000001371150312232120012454 0ustar00 AcmeBlogBundle:Blog:index Fixtures/directory/routes3.yml000064400000000033150312232120012473 0ustar00route3: path: /route/3 Fixtures/directory/recurse/routes2.yml000064400000000033150312232120014142 0ustar00route2: path: /route/2 Fixtures/directory/recurse/routes1.yml000064400000000033150312232120014141 0ustar00route1: path: /route/1 Fixtures/annotated.php000064400000000000150312232120011020 0ustar00Fixtures/CustomXmlFileLoader.php000064400000001157150312232120012743 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Fixtures; use Symfony\Component\Config\Util\XmlUtils; use Symfony\Component\Routing\Loader\XmlFileLoader; /** * XmlFileLoader with schema validation turned off. */ class CustomXmlFileLoader extends XmlFileLoader { protected function loadFile($file) { return XmlUtils::loadFile($file, function () { return true; }); } } Fixtures/file_resource.yml000064400000000000150312232120011703 0ustar00Fixtures/dumper/url_matcher4.php000064400000006634150312232120012753 0ustar00context = $context; } public function match($rawPathinfo) { $allow = []; $pathinfo = rawurldecode($rawPathinfo); $trimmedPathinfo = rtrim($pathinfo, '/'); $context = $this->context; $request = $this->request ?: $this->createRequest($pathinfo); $requestMethod = $canonicalMethod = $context->getMethod(); if ('HEAD' === $requestMethod) { $canonicalMethod = 'GET'; } // just_head if ('/just_head' === $pathinfo) { $ret = ['_route' => 'just_head']; if (!in_array($requestMethod, ['HEAD'])) { $allow = array_merge($allow, ['HEAD']); goto not_just_head; } return $ret; } not_just_head: // head_and_get if ('/head_and_get' === $pathinfo) { $ret = ['_route' => 'head_and_get']; if (!in_array($canonicalMethod, ['HEAD', 'GET'])) { $allow = array_merge($allow, ['HEAD', 'GET']); goto not_head_and_get; } return $ret; } not_head_and_get: // get_and_head if ('/get_and_head' === $pathinfo) { $ret = ['_route' => 'get_and_head']; if (!in_array($canonicalMethod, ['GET', 'HEAD'])) { $allow = array_merge($allow, ['GET', 'HEAD']); goto not_get_and_head; } return $ret; } not_get_and_head: // post_and_head if ('/post_and_head' === $pathinfo) { $ret = ['_route' => 'post_and_head']; if (!in_array($requestMethod, ['POST', 'HEAD'])) { $allow = array_merge($allow, ['POST', 'HEAD']); goto not_post_and_head; } return $ret; } not_post_and_head: if (0 === strpos($pathinfo, '/put_and_post')) { // put_and_post if ('/put_and_post' === $pathinfo) { $ret = ['_route' => 'put_and_post']; if (!in_array($requestMethod, ['PUT', 'POST'])) { $allow = array_merge($allow, ['PUT', 'POST']); goto not_put_and_post; } return $ret; } not_put_and_post: // put_and_get_and_head if ('/put_and_post' === $pathinfo) { $ret = ['_route' => 'put_and_get_and_head']; if (!in_array($canonicalMethod, ['PUT', 'GET', 'HEAD'])) { $allow = array_merge($allow, ['PUT', 'GET', 'HEAD']); goto not_put_and_get_and_head; } return $ret; } not_put_and_get_and_head: } if ('/' === $pathinfo && !$allow) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException(); } } Fixtures/dumper/url_matcher5.php000064400000015403150312232120012746 0ustar00context = $context; } public function match($rawPathinfo) { $allow = []; $pathinfo = rawurldecode($rawPathinfo); $trimmedPathinfo = rtrim($pathinfo, '/'); $context = $this->context; $request = $this->request ?: $this->createRequest($pathinfo); $requestMethod = $canonicalMethod = $context->getMethod(); if ('HEAD' === $requestMethod) { $canonicalMethod = 'GET'; } if (0 === strpos($pathinfo, '/a')) { // a_first if ('/a/11' === $pathinfo) { return ['_route' => 'a_first']; } // a_second if ('/a/22' === $pathinfo) { return ['_route' => 'a_second']; } // a_third if ('/a/333' === $pathinfo) { return ['_route' => 'a_third']; } } // a_wildcard if (preg_match('#^/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'a_wildcard']), array ()); } if (0 === strpos($pathinfo, '/a')) { // a_fourth if ('/a/44' === $trimmedPathinfo) { $ret = ['_route' => 'a_fourth']; if ('/' === substr($pathinfo, -1)) { // no-op } elseif ('GET' !== $canonicalMethod) { goto not_a_fourth; } else { return array_replace($ret, $this->redirect($rawPathinfo.'/', 'a_fourth')); } return $ret; } not_a_fourth: // a_fifth if ('/a/55' === $trimmedPathinfo) { $ret = ['_route' => 'a_fifth']; if ('/' === substr($pathinfo, -1)) { // no-op } elseif ('GET' !== $canonicalMethod) { goto not_a_fifth; } else { return array_replace($ret, $this->redirect($rawPathinfo.'/', 'a_fifth')); } return $ret; } not_a_fifth: // a_sixth if ('/a/66' === $trimmedPathinfo) { $ret = ['_route' => 'a_sixth']; if ('/' === substr($pathinfo, -1)) { // no-op } elseif ('GET' !== $canonicalMethod) { goto not_a_sixth; } else { return array_replace($ret, $this->redirect($rawPathinfo.'/', 'a_sixth')); } return $ret; } not_a_sixth: } // nested_wildcard if (0 === strpos($pathinfo, '/nested') && preg_match('#^/nested/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'nested_wildcard']), array ()); } if (0 === strpos($pathinfo, '/nested/group')) { // nested_a if ('/nested/group/a' === $trimmedPathinfo) { $ret = ['_route' => 'nested_a']; if ('/' === substr($pathinfo, -1)) { // no-op } elseif ('GET' !== $canonicalMethod) { goto not_nested_a; } else { return array_replace($ret, $this->redirect($rawPathinfo.'/', 'nested_a')); } return $ret; } not_nested_a: // nested_b if ('/nested/group/b' === $trimmedPathinfo) { $ret = ['_route' => 'nested_b']; if ('/' === substr($pathinfo, -1)) { // no-op } elseif ('GET' !== $canonicalMethod) { goto not_nested_b; } else { return array_replace($ret, $this->redirect($rawPathinfo.'/', 'nested_b')); } return $ret; } not_nested_b: // nested_c if ('/nested/group/c' === $trimmedPathinfo) { $ret = ['_route' => 'nested_c']; if ('/' === substr($pathinfo, -1)) { // no-op } elseif ('GET' !== $canonicalMethod) { goto not_nested_c; } else { return array_replace($ret, $this->redirect($rawPathinfo.'/', 'nested_c')); } return $ret; } not_nested_c: } elseif (0 === strpos($pathinfo, '/slashed/group')) { // slashed_a if ('/slashed/group' === $trimmedPathinfo) { $ret = ['_route' => 'slashed_a']; if ('/' === substr($pathinfo, -1)) { // no-op } elseif ('GET' !== $canonicalMethod) { goto not_slashed_a; } else { return array_replace($ret, $this->redirect($rawPathinfo.'/', 'slashed_a')); } return $ret; } not_slashed_a: // slashed_b if ('/slashed/group/b' === $trimmedPathinfo) { $ret = ['_route' => 'slashed_b']; if ('/' === substr($pathinfo, -1)) { // no-op } elseif ('GET' !== $canonicalMethod) { goto not_slashed_b; } else { return array_replace($ret, $this->redirect($rawPathinfo.'/', 'slashed_b')); } return $ret; } not_slashed_b: // slashed_c if ('/slashed/group/c' === $trimmedPathinfo) { $ret = ['_route' => 'slashed_c']; if ('/' === substr($pathinfo, -1)) { // no-op } elseif ('GET' !== $canonicalMethod) { goto not_slashed_c; } else { return array_replace($ret, $this->redirect($rawPathinfo.'/', 'slashed_c')); } return $ret; } not_slashed_c: } if ('/' === $pathinfo && !$allow) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException(); } } Fixtures/dumper/url_matcher6.php000064400000022353150312232120012751 0ustar00context = $context; } public function match($rawPathinfo) { $allow = []; $pathinfo = rawurldecode($rawPathinfo); $trimmedPathinfo = rtrim($pathinfo, '/'); $context = $this->context; $request = $this->request ?: $this->createRequest($pathinfo); $requestMethod = $canonicalMethod = $context->getMethod(); if ('HEAD' === $requestMethod) { $canonicalMethod = 'GET'; } if (0 === strpos($pathinfo, '/trailing/simple')) { // simple_trailing_slash_no_methods if ('/trailing/simple/no-methods/' === $pathinfo) { return ['_route' => 'simple_trailing_slash_no_methods']; } // simple_trailing_slash_GET_method if ('/trailing/simple/get-method/' === $pathinfo) { $ret = ['_route' => 'simple_trailing_slash_GET_method']; if (!in_array($canonicalMethod, ['GET'])) { $allow = array_merge($allow, ['GET']); goto not_simple_trailing_slash_GET_method; } return $ret; } not_simple_trailing_slash_GET_method: // simple_trailing_slash_HEAD_method if ('/trailing/simple/head-method/' === $pathinfo) { $ret = ['_route' => 'simple_trailing_slash_HEAD_method']; if (!in_array($requestMethod, ['HEAD'])) { $allow = array_merge($allow, ['HEAD']); goto not_simple_trailing_slash_HEAD_method; } return $ret; } not_simple_trailing_slash_HEAD_method: // simple_trailing_slash_POST_method if ('/trailing/simple/post-method/' === $pathinfo) { $ret = ['_route' => 'simple_trailing_slash_POST_method']; if (!in_array($requestMethod, ['POST'])) { $allow = array_merge($allow, ['POST']); goto not_simple_trailing_slash_POST_method; } return $ret; } not_simple_trailing_slash_POST_method: } elseif (0 === strpos($pathinfo, '/trailing/regex')) { // regex_trailing_slash_no_methods if (0 === strpos($pathinfo, '/trailing/regex/no-methods') && preg_match('#^/trailing/regex/no\\-methods/(?P[^/]++)/$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'regex_trailing_slash_no_methods']), array ()); } // regex_trailing_slash_GET_method if (0 === strpos($pathinfo, '/trailing/regex/get-method') && preg_match('#^/trailing/regex/get\\-method/(?P[^/]++)/$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'regex_trailing_slash_GET_method']), array ()); if (!in_array($canonicalMethod, ['GET'])) { $allow = array_merge($allow, ['GET']); goto not_regex_trailing_slash_GET_method; } return $ret; } not_regex_trailing_slash_GET_method: // regex_trailing_slash_HEAD_method if (0 === strpos($pathinfo, '/trailing/regex/head-method') && preg_match('#^/trailing/regex/head\\-method/(?P[^/]++)/$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'regex_trailing_slash_HEAD_method']), array ()); if (!in_array($requestMethod, ['HEAD'])) { $allow = array_merge($allow, ['HEAD']); goto not_regex_trailing_slash_HEAD_method; } return $ret; } not_regex_trailing_slash_HEAD_method: // regex_trailing_slash_POST_method if (0 === strpos($pathinfo, '/trailing/regex/post-method') && preg_match('#^/trailing/regex/post\\-method/(?P[^/]++)/$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'regex_trailing_slash_POST_method']), array ()); if (!in_array($requestMethod, ['POST'])) { $allow = array_merge($allow, ['POST']); goto not_regex_trailing_slash_POST_method; } return $ret; } not_regex_trailing_slash_POST_method: } elseif (0 === strpos($pathinfo, '/not-trailing/simple')) { // simple_not_trailing_slash_no_methods if ('/not-trailing/simple/no-methods' === $pathinfo) { return ['_route' => 'simple_not_trailing_slash_no_methods']; } // simple_not_trailing_slash_GET_method if ('/not-trailing/simple/get-method' === $pathinfo) { $ret = ['_route' => 'simple_not_trailing_slash_GET_method']; if (!in_array($canonicalMethod, ['GET'])) { $allow = array_merge($allow, ['GET']); goto not_simple_not_trailing_slash_GET_method; } return $ret; } not_simple_not_trailing_slash_GET_method: // simple_not_trailing_slash_HEAD_method if ('/not-trailing/simple/head-method' === $pathinfo) { $ret = ['_route' => 'simple_not_trailing_slash_HEAD_method']; if (!in_array($requestMethod, ['HEAD'])) { $allow = array_merge($allow, ['HEAD']); goto not_simple_not_trailing_slash_HEAD_method; } return $ret; } not_simple_not_trailing_slash_HEAD_method: // simple_not_trailing_slash_POST_method if ('/not-trailing/simple/post-method' === $pathinfo) { $ret = ['_route' => 'simple_not_trailing_slash_POST_method']; if (!in_array($requestMethod, ['POST'])) { $allow = array_merge($allow, ['POST']); goto not_simple_not_trailing_slash_POST_method; } return $ret; } not_simple_not_trailing_slash_POST_method: } elseif (0 === strpos($pathinfo, '/not-trailing/regex')) { // regex_not_trailing_slash_no_methods if (0 === strpos($pathinfo, '/not-trailing/regex/no-methods') && preg_match('#^/not\\-trailing/regex/no\\-methods/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'regex_not_trailing_slash_no_methods']), array ()); } // regex_not_trailing_slash_GET_method if (0 === strpos($pathinfo, '/not-trailing/regex/get-method') && preg_match('#^/not\\-trailing/regex/get\\-method/(?P[^/]++)$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'regex_not_trailing_slash_GET_method']), array ()); if (!in_array($canonicalMethod, ['GET'])) { $allow = array_merge($allow, ['GET']); goto not_regex_not_trailing_slash_GET_method; } return $ret; } not_regex_not_trailing_slash_GET_method: // regex_not_trailing_slash_HEAD_method if (0 === strpos($pathinfo, '/not-trailing/regex/head-method') && preg_match('#^/not\\-trailing/regex/head\\-method/(?P[^/]++)$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'regex_not_trailing_slash_HEAD_method']), array ()); if (!in_array($requestMethod, ['HEAD'])) { $allow = array_merge($allow, ['HEAD']); goto not_regex_not_trailing_slash_HEAD_method; } return $ret; } not_regex_not_trailing_slash_HEAD_method: // regex_not_trailing_slash_POST_method if (0 === strpos($pathinfo, '/not-trailing/regex/post-method') && preg_match('#^/not\\-trailing/regex/post\\-method/(?P[^/]++)$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'regex_not_trailing_slash_POST_method']), array ()); if (!in_array($requestMethod, ['POST'])) { $allow = array_merge($allow, ['POST']); goto not_regex_not_trailing_slash_POST_method; } return $ret; } not_regex_not_trailing_slash_POST_method: } if ('/' === $pathinfo && !$allow) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException(); } } Fixtures/dumper/url_matcher3.php000064400000003334150312232120012744 0ustar00context = $context; } public function match($rawPathinfo) { $allow = []; $pathinfo = rawurldecode($rawPathinfo); $trimmedPathinfo = rtrim($pathinfo, '/'); $context = $this->context; $request = $this->request ?: $this->createRequest($pathinfo); $requestMethod = $canonicalMethod = $context->getMethod(); if ('HEAD' === $requestMethod) { $canonicalMethod = 'GET'; } if (0 === strpos($pathinfo, '/rootprefix')) { // static if ('/rootprefix/test' === $pathinfo) { return ['_route' => 'static']; } // dynamic if (preg_match('#^/rootprefix/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'dynamic']), array ()); } } // with-condition if ('/with-condition' === $pathinfo && ($context->getMethod() == "GET")) { return ['_route' => 'with-condition']; } if ('/' === $pathinfo && !$allow) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException(); } } Fixtures/dumper/url_matcher2.php000064400000032036150312232120012744 0ustar00context = $context; } public function match($rawPathinfo) { $allow = []; $pathinfo = rawurldecode($rawPathinfo); $trimmedPathinfo = rtrim($pathinfo, '/'); $context = $this->context; $request = $this->request ?: $this->createRequest($pathinfo); $requestMethod = $canonicalMethod = $context->getMethod(); if ('HEAD' === $requestMethod) { $canonicalMethod = 'GET'; } if (0 === strpos($pathinfo, '/foo')) { // foo if (preg_match('#^/foo/(?Pbaz|symfony)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'foo']), array ( 'def' => 'test',)); } // foofoo if ('/foofoo' === $pathinfo) { return array ( 'def' => 'test', '_route' => 'foofoo',); } } elseif (0 === strpos($pathinfo, '/bar')) { // bar if (preg_match('#^/bar/(?P[^/]++)$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'bar']), array ()); if (!in_array($canonicalMethod, ['GET', 'HEAD'])) { $allow = array_merge($allow, ['GET', 'HEAD']); goto not_bar; } return $ret; } not_bar: // barhead if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?P[^/]++)$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'barhead']), array ()); if (!in_array($canonicalMethod, ['GET'])) { $allow = array_merge($allow, ['GET']); goto not_barhead; } return $ret; } not_barhead: } elseif (0 === strpos($pathinfo, '/test')) { if (0 === strpos($pathinfo, '/test/baz')) { // baz if ('/test/baz' === $pathinfo) { return ['_route' => 'baz']; } // baz2 if ('/test/baz.html' === $pathinfo) { return ['_route' => 'baz2']; } // baz3 if ('/test/baz3' === $trimmedPathinfo) { $ret = ['_route' => 'baz3']; if ('/' === substr($pathinfo, -1)) { // no-op } elseif ('GET' !== $canonicalMethod) { goto not_baz3; } else { return array_replace($ret, $this->redirect($rawPathinfo.'/', 'baz3')); } return $ret; } not_baz3: } // baz4 if (preg_match('#^/test/(?P[^/]++)/?$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'baz4']), array ()); if ('/' === substr($pathinfo, -1)) { // no-op } elseif ('GET' !== $canonicalMethod) { goto not_baz4; } else { return array_replace($ret, $this->redirect($rawPathinfo.'/', 'baz4')); } return $ret; } not_baz4: // baz5 if (preg_match('#^/test/(?P[^/]++)/$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'baz5']), array ()); if (!in_array($requestMethod, ['POST'])) { $allow = array_merge($allow, ['POST']); goto not_baz5; } return $ret; } not_baz5: // baz.baz6 if (preg_match('#^/test/(?P[^/]++)/$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'baz.baz6']), array ()); if (!in_array($requestMethod, ['PUT'])) { $allow = array_merge($allow, ['PUT']); goto not_bazbaz6; } return $ret; } not_bazbaz6: } // quoter if (preg_match('#^/(?P[\']+)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'quoter']), array ()); } // space if ('/spa ce' === $pathinfo) { return ['_route' => 'space']; } if (0 === strpos($pathinfo, '/a')) { if (0 === strpos($pathinfo, '/a/b\'b')) { // foo1 if (preg_match('#^/a/b\'b/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'foo1']), array ()); } // bar1 if (preg_match('#^/a/b\'b/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'bar1']), array ()); } } // overridden if (preg_match('#^/a/(?P.*)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'overridden']), array ()); } if (0 === strpos($pathinfo, '/a/b\'b')) { // foo2 if (preg_match('#^/a/b\'b/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'foo2']), array ()); } // bar2 if (preg_match('#^/a/b\'b/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'bar2']), array ()); } } } elseif (0 === strpos($pathinfo, '/multi')) { // helloWorld if (0 === strpos($pathinfo, '/multi/hello') && preg_match('#^/multi/hello(?:/(?P[^/]++))?$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'helloWorld']), array ( 'who' => 'World!',)); } // hey if ('/multi/hey' === $trimmedPathinfo) { $ret = ['_route' => 'hey']; if ('/' === substr($pathinfo, -1)) { // no-op } elseif ('GET' !== $canonicalMethod) { goto not_hey; } else { return array_replace($ret, $this->redirect($rawPathinfo.'/', 'hey')); } return $ret; } not_hey: // overridden2 if ('/multi/new' === $pathinfo) { return ['_route' => 'overridden2']; } } // foo3 if (preg_match('#^/(?P<_locale>[^/]++)/b/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'foo3']), array ()); } // bar3 if (preg_match('#^/(?P<_locale>[^/]++)/b/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'bar3']), array ()); } if (0 === strpos($pathinfo, '/aba')) { // ababa if ('/ababa' === $pathinfo) { return ['_route' => 'ababa']; } // foo4 if (preg_match('#^/aba/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'foo4']), array ()); } } $host = $context->getHost(); if (preg_match('#^a\\.example\\.com$#sDi', $host, $hostMatches)) { // route1 if ('/route1' === $pathinfo) { return ['_route' => 'route1']; } // route2 if ('/c2/route2' === $pathinfo) { return ['_route' => 'route2']; } } if (preg_match('#^b\\.example\\.com$#sDi', $host, $hostMatches)) { // route3 if ('/c2/route3' === $pathinfo) { return ['_route' => 'route3']; } } if (preg_match('#^a\\.example\\.com$#sDi', $host, $hostMatches)) { // route4 if ('/route4' === $pathinfo) { return ['_route' => 'route4']; } } if (preg_match('#^c\\.example\\.com$#sDi', $host, $hostMatches)) { // route5 if ('/route5' === $pathinfo) { return ['_route' => 'route5']; } } // route6 if ('/route6' === $pathinfo) { return ['_route' => 'route6']; } if (preg_match('#^(?P[^\\.]++)\\.example\\.com$#sDi', $host, $hostMatches)) { if (0 === strpos($pathinfo, '/route1')) { // route11 if ('/route11' === $pathinfo) { return $this->mergeDefaults(array_replace($hostMatches, ['_route' => 'route11']), array ()); } // route12 if ('/route12' === $pathinfo) { return $this->mergeDefaults(array_replace($hostMatches, ['_route' => 'route12']), array ( 'var1' => 'val',)); } // route13 if (0 === strpos($pathinfo, '/route13') && preg_match('#^/route13/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($hostMatches, $matches, ['_route' => 'route13']), array ()); } // route14 if (0 === strpos($pathinfo, '/route14') && preg_match('#^/route14/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($hostMatches, $matches, ['_route' => 'route14']), array ( 'var1' => 'val',)); } } } if (preg_match('#^c\\.example\\.com$#sDi', $host, $hostMatches)) { // route15 if (0 === strpos($pathinfo, '/route15') && preg_match('#^/route15/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'route15']), array ()); } } // route16 if (0 === strpos($pathinfo, '/route16') && preg_match('#^/route16/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'route16']), array ( 'var1' => 'val',)); } // route17 if ('/route17' === $pathinfo) { return ['_route' => 'route17']; } // a if ('/a/a...' === $pathinfo) { return ['_route' => 'a']; } if (0 === strpos($pathinfo, '/a/b')) { // b if (preg_match('#^/a/b/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'b']), array ()); } // c if (0 === strpos($pathinfo, '/a/b/c') && preg_match('#^/a/b/c/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'c']), array ()); } } // secure if ('/secure' === $pathinfo) { $ret = ['_route' => 'secure']; $requiredSchemes = array ( 'https' => 0,); if (!isset($requiredSchemes[$context->getScheme()])) { if ('GET' !== $canonicalMethod) { goto not_secure; } return array_replace($ret, $this->redirect($rawPathinfo, 'secure', key($requiredSchemes))); } return $ret; } not_secure: // nonsecure if ('/nonsecure' === $pathinfo) { $ret = ['_route' => 'nonsecure']; $requiredSchemes = array ( 'http' => 0,); if (!isset($requiredSchemes[$context->getScheme()])) { if ('GET' !== $canonicalMethod) { goto not_nonsecure; } return array_replace($ret, $this->redirect($rawPathinfo, 'nonsecure', key($requiredSchemes))); } return $ret; } not_nonsecure: if ('/' === $pathinfo && !$allow) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException(); } } Fixtures/dumper/url_matcher7.php000064400000025525150312232120012756 0ustar00context = $context; } public function match($rawPathinfo) { $allow = []; $pathinfo = rawurldecode($rawPathinfo); $trimmedPathinfo = rtrim($pathinfo, '/'); $context = $this->context; $request = $this->request ?: $this->createRequest($pathinfo); $requestMethod = $canonicalMethod = $context->getMethod(); if ('HEAD' === $requestMethod) { $canonicalMethod = 'GET'; } if (0 === strpos($pathinfo, '/trailing/simple')) { // simple_trailing_slash_no_methods if ('/trailing/simple/no-methods' === $trimmedPathinfo) { $ret = ['_route' => 'simple_trailing_slash_no_methods']; if ('/' === substr($pathinfo, -1)) { // no-op } elseif ('GET' !== $canonicalMethod) { goto not_simple_trailing_slash_no_methods; } else { return array_replace($ret, $this->redirect($rawPathinfo.'/', 'simple_trailing_slash_no_methods')); } return $ret; } not_simple_trailing_slash_no_methods: // simple_trailing_slash_GET_method if ('/trailing/simple/get-method' === $trimmedPathinfo) { $ret = ['_route' => 'simple_trailing_slash_GET_method']; if ('/' === substr($pathinfo, -1)) { // no-op } elseif ('GET' !== $canonicalMethod) { goto not_simple_trailing_slash_GET_method; } else { return array_replace($ret, $this->redirect($rawPathinfo.'/', 'simple_trailing_slash_GET_method')); } if (!in_array($canonicalMethod, ['GET'])) { $allow = array_merge($allow, ['GET']); goto not_simple_trailing_slash_GET_method; } return $ret; } not_simple_trailing_slash_GET_method: // simple_trailing_slash_HEAD_method if ('/trailing/simple/head-method/' === $pathinfo) { $ret = ['_route' => 'simple_trailing_slash_HEAD_method']; if (!in_array($requestMethod, ['HEAD'])) { $allow = array_merge($allow, ['HEAD']); goto not_simple_trailing_slash_HEAD_method; } return $ret; } not_simple_trailing_slash_HEAD_method: // simple_trailing_slash_POST_method if ('/trailing/simple/post-method/' === $pathinfo) { $ret = ['_route' => 'simple_trailing_slash_POST_method']; if (!in_array($requestMethod, ['POST'])) { $allow = array_merge($allow, ['POST']); goto not_simple_trailing_slash_POST_method; } return $ret; } not_simple_trailing_slash_POST_method: } elseif (0 === strpos($pathinfo, '/trailing/regex')) { // regex_trailing_slash_no_methods if (0 === strpos($pathinfo, '/trailing/regex/no-methods') && preg_match('#^/trailing/regex/no\\-methods/(?P[^/]++)/?$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'regex_trailing_slash_no_methods']), array ()); if ('/' === substr($pathinfo, -1)) { // no-op } elseif ('GET' !== $canonicalMethod) { goto not_regex_trailing_slash_no_methods; } else { return array_replace($ret, $this->redirect($rawPathinfo.'/', 'regex_trailing_slash_no_methods')); } return $ret; } not_regex_trailing_slash_no_methods: // regex_trailing_slash_GET_method if (0 === strpos($pathinfo, '/trailing/regex/get-method') && preg_match('#^/trailing/regex/get\\-method/(?P[^/]++)/?$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'regex_trailing_slash_GET_method']), array ()); if ('/' === substr($pathinfo, -1)) { // no-op } elseif ('GET' !== $canonicalMethod) { goto not_regex_trailing_slash_GET_method; } else { return array_replace($ret, $this->redirect($rawPathinfo.'/', 'regex_trailing_slash_GET_method')); } if (!in_array($canonicalMethod, ['GET'])) { $allow = array_merge($allow, ['GET']); goto not_regex_trailing_slash_GET_method; } return $ret; } not_regex_trailing_slash_GET_method: // regex_trailing_slash_HEAD_method if (0 === strpos($pathinfo, '/trailing/regex/head-method') && preg_match('#^/trailing/regex/head\\-method/(?P[^/]++)/$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'regex_trailing_slash_HEAD_method']), array ()); if (!in_array($requestMethod, ['HEAD'])) { $allow = array_merge($allow, ['HEAD']); goto not_regex_trailing_slash_HEAD_method; } return $ret; } not_regex_trailing_slash_HEAD_method: // regex_trailing_slash_POST_method if (0 === strpos($pathinfo, '/trailing/regex/post-method') && preg_match('#^/trailing/regex/post\\-method/(?P[^/]++)/$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'regex_trailing_slash_POST_method']), array ()); if (!in_array($requestMethod, ['POST'])) { $allow = array_merge($allow, ['POST']); goto not_regex_trailing_slash_POST_method; } return $ret; } not_regex_trailing_slash_POST_method: } elseif (0 === strpos($pathinfo, '/not-trailing/simple')) { // simple_not_trailing_slash_no_methods if ('/not-trailing/simple/no-methods' === $pathinfo) { return ['_route' => 'simple_not_trailing_slash_no_methods']; } // simple_not_trailing_slash_GET_method if ('/not-trailing/simple/get-method' === $pathinfo) { $ret = ['_route' => 'simple_not_trailing_slash_GET_method']; if (!in_array($canonicalMethod, ['GET'])) { $allow = array_merge($allow, ['GET']); goto not_simple_not_trailing_slash_GET_method; } return $ret; } not_simple_not_trailing_slash_GET_method: // simple_not_trailing_slash_HEAD_method if ('/not-trailing/simple/head-method' === $pathinfo) { $ret = ['_route' => 'simple_not_trailing_slash_HEAD_method']; if (!in_array($requestMethod, ['HEAD'])) { $allow = array_merge($allow, ['HEAD']); goto not_simple_not_trailing_slash_HEAD_method; } return $ret; } not_simple_not_trailing_slash_HEAD_method: // simple_not_trailing_slash_POST_method if ('/not-trailing/simple/post-method' === $pathinfo) { $ret = ['_route' => 'simple_not_trailing_slash_POST_method']; if (!in_array($requestMethod, ['POST'])) { $allow = array_merge($allow, ['POST']); goto not_simple_not_trailing_slash_POST_method; } return $ret; } not_simple_not_trailing_slash_POST_method: } elseif (0 === strpos($pathinfo, '/not-trailing/regex')) { // regex_not_trailing_slash_no_methods if (0 === strpos($pathinfo, '/not-trailing/regex/no-methods') && preg_match('#^/not\\-trailing/regex/no\\-methods/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'regex_not_trailing_slash_no_methods']), array ()); } // regex_not_trailing_slash_GET_method if (0 === strpos($pathinfo, '/not-trailing/regex/get-method') && preg_match('#^/not\\-trailing/regex/get\\-method/(?P[^/]++)$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'regex_not_trailing_slash_GET_method']), array ()); if (!in_array($canonicalMethod, ['GET'])) { $allow = array_merge($allow, ['GET']); goto not_regex_not_trailing_slash_GET_method; } return $ret; } not_regex_not_trailing_slash_GET_method: // regex_not_trailing_slash_HEAD_method if (0 === strpos($pathinfo, '/not-trailing/regex/head-method') && preg_match('#^/not\\-trailing/regex/head\\-method/(?P[^/]++)$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'regex_not_trailing_slash_HEAD_method']), array ()); if (!in_array($requestMethod, ['HEAD'])) { $allow = array_merge($allow, ['HEAD']); goto not_regex_not_trailing_slash_HEAD_method; } return $ret; } not_regex_not_trailing_slash_HEAD_method: // regex_not_trailing_slash_POST_method if (0 === strpos($pathinfo, '/not-trailing/regex/post-method') && preg_match('#^/not\\-trailing/regex/post\\-method/(?P[^/]++)$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'regex_not_trailing_slash_POST_method']), array ()); if (!in_array($requestMethod, ['POST'])) { $allow = array_merge($allow, ['POST']); goto not_regex_not_trailing_slash_POST_method; } return $ret; } not_regex_not_trailing_slash_POST_method: } if ('/' === $pathinfo && !$allow) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException(); } } Fixtures/dumper/url_matcher0.php000064400000002201150312232120012731 0ustar00context = $context; } public function match($rawPathinfo) { $allow = []; $pathinfo = rawurldecode($rawPathinfo); $trimmedPathinfo = rtrim($pathinfo, '/'); $context = $this->context; $request = $this->request ?: $this->createRequest($pathinfo); $requestMethod = $canonicalMethod = $context->getMethod(); if ('HEAD' === $requestMethod) { $canonicalMethod = 'GET'; } if ('/' === $pathinfo && !$allow) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException(); } } Fixtures/dumper/url_matcher1.php000064400000025637150312232120012754 0ustar00context = $context; } public function match($rawPathinfo) { $allow = []; $pathinfo = rawurldecode($rawPathinfo); $trimmedPathinfo = rtrim($pathinfo, '/'); $context = $this->context; $request = $this->request ?: $this->createRequest($pathinfo); $requestMethod = $canonicalMethod = $context->getMethod(); if ('HEAD' === $requestMethod) { $canonicalMethod = 'GET'; } if (0 === strpos($pathinfo, '/foo')) { // foo if (preg_match('#^/foo/(?Pbaz|symfony)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'foo']), array ( 'def' => 'test',)); } // foofoo if ('/foofoo' === $pathinfo) { return array ( 'def' => 'test', '_route' => 'foofoo',); } } elseif (0 === strpos($pathinfo, '/bar')) { // bar if (preg_match('#^/bar/(?P[^/]++)$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'bar']), array ()); if (!in_array($canonicalMethod, ['GET', 'HEAD'])) { $allow = array_merge($allow, ['GET', 'HEAD']); goto not_bar; } return $ret; } not_bar: // barhead if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?P[^/]++)$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'barhead']), array ()); if (!in_array($canonicalMethod, ['GET'])) { $allow = array_merge($allow, ['GET']); goto not_barhead; } return $ret; } not_barhead: } elseif (0 === strpos($pathinfo, '/test')) { if (0 === strpos($pathinfo, '/test/baz')) { // baz if ('/test/baz' === $pathinfo) { return ['_route' => 'baz']; } // baz2 if ('/test/baz.html' === $pathinfo) { return ['_route' => 'baz2']; } // baz3 if ('/test/baz3/' === $pathinfo) { return ['_route' => 'baz3']; } } // baz4 if (preg_match('#^/test/(?P[^/]++)/$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'baz4']), array ()); } // baz5 if (preg_match('#^/test/(?P[^/]++)/$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'baz5']), array ()); if (!in_array($requestMethod, ['POST'])) { $allow = array_merge($allow, ['POST']); goto not_baz5; } return $ret; } not_baz5: // baz.baz6 if (preg_match('#^/test/(?P[^/]++)/$#sD', $pathinfo, $matches)) { $ret = $this->mergeDefaults(array_replace($matches, ['_route' => 'baz.baz6']), array ()); if (!in_array($requestMethod, ['PUT'])) { $allow = array_merge($allow, ['PUT']); goto not_bazbaz6; } return $ret; } not_bazbaz6: } // quoter if (preg_match('#^/(?P[\']+)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'quoter']), array ()); } // space if ('/spa ce' === $pathinfo) { return ['_route' => 'space']; } if (0 === strpos($pathinfo, '/a')) { if (0 === strpos($pathinfo, '/a/b\'b')) { // foo1 if (preg_match('#^/a/b\'b/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'foo1']), array ()); } // bar1 if (preg_match('#^/a/b\'b/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'bar1']), array ()); } } // overridden if (preg_match('#^/a/(?P.*)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'overridden']), array ()); } if (0 === strpos($pathinfo, '/a/b\'b')) { // foo2 if (preg_match('#^/a/b\'b/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'foo2']), array ()); } // bar2 if (preg_match('#^/a/b\'b/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'bar2']), array ()); } } } elseif (0 === strpos($pathinfo, '/multi')) { // helloWorld if (0 === strpos($pathinfo, '/multi/hello') && preg_match('#^/multi/hello(?:/(?P[^/]++))?$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'helloWorld']), array ( 'who' => 'World!',)); } // hey if ('/multi/hey/' === $pathinfo) { return ['_route' => 'hey']; } // overridden2 if ('/multi/new' === $pathinfo) { return ['_route' => 'overridden2']; } } // foo3 if (preg_match('#^/(?P<_locale>[^/]++)/b/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'foo3']), array ()); } // bar3 if (preg_match('#^/(?P<_locale>[^/]++)/b/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'bar3']), array ()); } if (0 === strpos($pathinfo, '/aba')) { // ababa if ('/ababa' === $pathinfo) { return ['_route' => 'ababa']; } // foo4 if (preg_match('#^/aba/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'foo4']), array ()); } } $host = $context->getHost(); if (preg_match('#^a\\.example\\.com$#sDi', $host, $hostMatches)) { // route1 if ('/route1' === $pathinfo) { return ['_route' => 'route1']; } // route2 if ('/c2/route2' === $pathinfo) { return ['_route' => 'route2']; } } if (preg_match('#^b\\.example\\.com$#sDi', $host, $hostMatches)) { // route3 if ('/c2/route3' === $pathinfo) { return ['_route' => 'route3']; } } if (preg_match('#^a\\.example\\.com$#sDi', $host, $hostMatches)) { // route4 if ('/route4' === $pathinfo) { return ['_route' => 'route4']; } } if (preg_match('#^c\\.example\\.com$#sDi', $host, $hostMatches)) { // route5 if ('/route5' === $pathinfo) { return ['_route' => 'route5']; } } // route6 if ('/route6' === $pathinfo) { return ['_route' => 'route6']; } if (preg_match('#^(?P[^\\.]++)\\.example\\.com$#sDi', $host, $hostMatches)) { if (0 === strpos($pathinfo, '/route1')) { // route11 if ('/route11' === $pathinfo) { return $this->mergeDefaults(array_replace($hostMatches, ['_route' => 'route11']), array ()); } // route12 if ('/route12' === $pathinfo) { return $this->mergeDefaults(array_replace($hostMatches, ['_route' => 'route12']), array ( 'var1' => 'val',)); } // route13 if (0 === strpos($pathinfo, '/route13') && preg_match('#^/route13/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($hostMatches, $matches, ['_route' => 'route13']), array ()); } // route14 if (0 === strpos($pathinfo, '/route14') && preg_match('#^/route14/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($hostMatches, $matches, ['_route' => 'route14']), array ( 'var1' => 'val',)); } } } if (preg_match('#^c\\.example\\.com$#sDi', $host, $hostMatches)) { // route15 if (0 === strpos($pathinfo, '/route15') && preg_match('#^/route15/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'route15']), array ()); } } // route16 if (0 === strpos($pathinfo, '/route16') && preg_match('#^/route16/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'route16']), array ( 'var1' => 'val',)); } // route17 if ('/route17' === $pathinfo) { return ['_route' => 'route17']; } // a if ('/a/a...' === $pathinfo) { return ['_route' => 'a']; } if (0 === strpos($pathinfo, '/a/b')) { // b if (preg_match('#^/a/b/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'b']), array ()); } // c if (0 === strpos($pathinfo, '/a/b/c') && preg_match('#^/a/b/c/(?P[^/]++)$#sD', $pathinfo, $matches)) { return $this->mergeDefaults(array_replace($matches, ['_route' => 'c']), array ()); } } if ('/' === $pathinfo && !$allow) { throw new Symfony\Component\Routing\Exception\NoConfigurationException(); } throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException(); } } Fixtures/namespaceprefix.xml000064400000001477150312232120012251 0ustar00 MyBundle:Blog:show \w+ en|fr|de RouteCompiler 1 Fixtures/nonesense_type_without_resource.yml000064400000000071150312232120015615 0ustar00blog_show: path: /blog/{slug} type: custom Fixtures/nonvalidkeys.yml000064400000000075150312232120011577 0ustar00someroute: resource: path/to/some.yml name_prefix: test_ Fixtures/validpattern.yml000064400000000624150312232120011566 0ustar00blog_show: path: /blog/{slug} defaults: { _controller: "MyBundle:Blog:show" } host: "{locale}.example.com" requirements: { 'locale': '\w+' } methods: ['GET','POST','put','OpTiOnS'] schemes: ['https'] condition: 'context.getMethod() == "GET"' options: compiler_class: RouteCompiler blog_show_inherited: path: /blog/{slug} Fixtures/null_values.xml000064400000001022150312232120011412 0ustar00 foo bar Fixtures/validresource.xml000064400000001034150312232120011733 0ustar00 123 \d+ context.getMethod() == "POST" Fixtures/map_in_list_defaults.xml000064400000001401150312232120013247 0ustar00 AcmeBlogBundle:Blog:index true 1 3.5 foo Fixtures/foo.xml000064400000000000150312232120007637 0ustar00Fixtures/nonesense_resource_plus_path.yml000064400000000076150312232120015055 0ustar00blog_show: resource: validpattern.yml path: /test Fixtures/validpattern.xml000064400000001277150312232120011572 0ustar00 MyBundle:Blog:show \w+ context.getMethod() == "GET" Fixtures/list_in_list_defaults.xml000064400000001323150312232120013450 0ustar00 AcmeBlogBundle:Blog:index true 1 3.5 foo Fixtures/special_route_name.yml000064400000000037150312232120012725 0ustar00"#$péß^a|": path: "true" Fixtures/list_in_map_defaults.xml000064400000001334150312232120013254 0ustar00 AcmeBlogBundle:Blog:index true 1 3.5 foo Fixtures/scalar_defaults.xml000064400000002020150312232120012214 0ustar00 AcmeBlogBundle:Blog:index true 1 3.5 false 1 0 Fixtures/RedirectableUrlMatcher.php000064400000001424150312232120013432 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Fixtures; use Symfony\Component\Routing\Matcher\RedirectableUrlMatcherInterface; use Symfony\Component\Routing\Matcher\UrlMatcher; /** * @author Fabien Potencier */ class RedirectableUrlMatcher extends UrlMatcher implements RedirectableUrlMatcherInterface { public function redirect($path, $route, $scheme = null) { return [ '_controller' => 'Some controller reference...', 'path' => $path, 'scheme' => $scheme, ]; } } Fixtures/controller/override_defaults.yml000064400000000172150312232120014760 0ustar00app_blog: path: /blog controller: AppBundle:Homepage:show defaults: _controller: AppBundle:Blog:index Fixtures/controller/routing.xml000064400000001010150312232120012730 0ustar00 AppBundle:Blog:list Fixtures/controller/import_controller.xml000064400000000553150312232120015031 0ustar00 Fixtures/controller/import__controller.yml000064400000000150150312232120015162 0ustar00_static: resource: routing.yml defaults: _controller: FrameworkBundle:Template:template Fixtures/controller/import_override_defaults.xml000064400000000671150312232120016355 0ustar00 AppBundle:Blog:index Fixtures/controller/import__controller.xml000064400000000627150312232120015172 0ustar00 FrameworkBundle:Template:template Fixtures/controller/import_controller.yml000064400000000125150312232120015025 0ustar00_static: resource: routing.yml controller: FrameworkBundle:Template:template Fixtures/controller/routing.yml000064400000000263150312232120012742 0ustar00app_homepage: path: / controller: AppBundle:Homepage:show app_blog: path: /blog defaults: _controller: AppBundle:Blog:list app_logout: path: /logout Fixtures/controller/import_override_defaults.yml000064400000000220150312232120016344 0ustar00_static: resource: routing.yml controller: FrameworkBundle:Template:template defaults: _controller: AppBundle:Homepage:show Fixtures/controller/override_defaults.xml000064400000000661150312232120014762 0ustar00 AppBundle:Blog:index Fixtures/nonvalid.xml000064400000000624150312232120010702 0ustar00 MyBundle:Blog:show Fixtures/map_null_values.xml000064400000001510150312232120012251 0ustar00 AcmeBlogBundle:Blog:index Fixtures/glob/import_single.yml000064400000000037150312232120012665 0ustar00_static: resource: b?r.yml Fixtures/glob/php_dsl_bar.php000064400000000436150312232120012260 0ustar00collection(); $collection->add('bar_route', '/bar') ->defaults(['_controller' => 'AppBundle:Bar:view']); return $collection; }; Fixtures/glob/bar.xml000064400000000547150312232120010563 0ustar00 Fixtures/glob/import_multiple.xml000064400000000500150312232120013231 0ustar00 Fixtures/glob/baz.yml000064400000000120150312232120010557 0ustar00baz_route: path: /baz defaults: _controller: AppBundle:Baz:view Fixtures/glob/php_dsl.php000064400000000243150312232120011430 0ustar00import('php_dsl_ba?.php'); }; Fixtures/glob/php_dsl_baz.php000064400000000436150312232120012270 0ustar00collection(); $collection->add('baz_route', '/baz') ->defaults(['_controller' => 'AppBundle:Baz:view']); return $collection; }; Fixtures/glob/baz.xml000064400000000547150312232120010573 0ustar00 Fixtures/glob/import_multiple.yml000064400000000037150312232120013237 0ustar00_static: resource: ba?.yml Fixtures/glob/import_single.xml000064400000000500150312232120012657 0ustar00 Fixtures/glob/bar.yml000064400000000120150312232120010547 0ustar00bar_route: path: /bar defaults: _controller: AppBundle:Bar:view Fixtures/CustomCompiledRoute.php000064400000000605150312232120013024 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Fixtures; use Symfony\Component\Routing\CompiledRoute; class CustomCompiledRoute extends CompiledRoute { } Fixtures/validpattern.php000064400000000701150312232120011550 0ustar00add('blog_show', new Route( '/blog/{slug}', ['_controller' => 'MyBlogBundle:Blog:show'], ['locale' => '\w+'], ['compiler_class' => 'RouteCompiler'], '{locale}.example.com', ['https'], ['GET', 'POST', 'put', 'OpTiOnS'], 'context.getMethod() == "GET"' )); return $collection; Fixtures/validresource.yml000064400000000363150312232120011740 0ustar00_blog: resource: validpattern.yml prefix: /{foo} defaults: { 'foo': '123' } requirements: { 'foo': '\d+' } options: { 'foo': 'bar' } host: "" condition: 'context.getMethod() == "POST"' Fixtures/missing_path.xml000064400000000460150312232120011553 0ustar00 Fixtures/CustomRouteCompiler.php000064400000001104150312232120013035 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Fixtures; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCompiler; class CustomRouteCompiler extends RouteCompiler { /** * {@inheritdoc} */ public static function compile(Route $route) { return new CustomCompiledRoute('', '', [], []); } } Fixtures/nonvalidnode.xml000064400000000442150312232120011546 0ustar00 bar Fixtures/nonvalidroute.xml000064400000000750150312232120011761 0ustar00 MyBundle:Blog:show baz Fixtures/nonvalid.yml000064400000000004150312232120010673 0ustar00foo Fixtures/nonvalid2.yml000064400000000016150312232120010760 0ustar00route: string Fixtures/directory_import/import.yml000064400000000075150312232120014001 0ustar00_directory: resource: "../directory" type: directory Fixtures/php_dsl_sub.php000064400000000436150312232120011362 0ustar00collection('c_') ->prefix('pub'); $add('bar', '/bar'); $add->collection('pub_') ->host('host') ->add('buz', 'buz'); }; Fixtures/bad_format.yml000064400000000124150312232120011162 0ustar00blog_show: path: /blog/{slug} defaults: { _controller: "MyBundle:Blog:show" } Fixtures/list_defaults.xml000064400000001224150312232120011727 0ustar00 AcmeBlogBundle:Blog:index true 1 3.5 foo Fixtures/empty.yml000064400000000000150312232120010213 0ustar00Annotation/RouteTest.php000064400000002660150312232120011320 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Annotation; use PHPUnit\Framework\TestCase; use Symfony\Component\Routing\Annotation\Route; class RouteTest extends TestCase { public function testInvalidRouteParameter() { $this->expectException('BadMethodCallException'); new Route(['foo' => 'bar']); } /** * @dataProvider getValidParameters */ public function testRouteParameters($parameter, $value, $getter) { $route = new Route([$parameter => $value]); $this->assertEquals($route->$getter(), $value); } public function getValidParameters() { return [ ['value', '/Blog', 'getPath'], ['requirements', ['locale' => 'en'], 'getRequirements'], ['options', ['compiler_class' => 'RouteCompiler'], 'getOptions'], ['name', 'blog_index', 'getName'], ['defaults', ['_controller' => 'MyBlogBundle:Blog:index'], 'getDefaults'], ['schemes', ['https'], 'getSchemes'], ['methods', ['GET', 'POST'], 'getMethods'], ['host', '{locale}.example.com', 'getHost'], ['condition', 'context.getMethod() == "GET"', 'getCondition'], ]; } } RouterTest.php000064400000011716150312232120007372 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Router; class RouterTest extends TestCase { private $router = null; private $loader = null; protected function setUp() { $this->loader = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderInterface')->getMock(); $this->router = new Router($this->loader, 'routing.yml'); } public function testSetOptionsWithSupportedOptions() { $this->router->setOptions([ 'cache_dir' => './cache', 'debug' => true, 'resource_type' => 'ResourceType', ]); $this->assertSame('./cache', $this->router->getOption('cache_dir')); $this->assertTrue($this->router->getOption('debug')); $this->assertSame('ResourceType', $this->router->getOption('resource_type')); } public function testSetOptionsWithUnsupportedOptions() { $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage('The Router does not support the following options: "option_foo", "option_bar"'); $this->router->setOptions([ 'cache_dir' => './cache', 'option_foo' => true, 'option_bar' => 'baz', 'resource_type' => 'ResourceType', ]); } public function testSetOptionWithSupportedOption() { $this->router->setOption('cache_dir', './cache'); $this->assertSame('./cache', $this->router->getOption('cache_dir')); } public function testSetOptionWithUnsupportedOption() { $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage('The Router does not support the "option_foo" option'); $this->router->setOption('option_foo', true); } public function testGetOptionWithUnsupportedOption() { $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage('The Router does not support the "option_foo" option'); $this->router->getOption('option_foo', true); } public function testThatRouteCollectionIsLoaded() { $this->router->setOption('resource_type', 'ResourceType'); $routeCollection = new RouteCollection(); $this->loader->expects($this->once()) ->method('load')->with('routing.yml', 'ResourceType') ->willReturn($routeCollection); $this->assertSame($routeCollection, $this->router->getRouteCollection()); } /** * @dataProvider provideMatcherOptionsPreventingCaching */ public function testMatcherIsCreatedIfCacheIsNotConfigured($option) { $this->router->setOption($option, null); $this->loader->expects($this->once()) ->method('load')->with('routing.yml', null) ->willReturn(new RouteCollection()); $this->assertInstanceOf('Symfony\\Component\\Routing\\Matcher\\UrlMatcher', $this->router->getMatcher()); } public function provideMatcherOptionsPreventingCaching() { return [ ['cache_dir'], ['matcher_cache_class'], ]; } /** * @dataProvider provideGeneratorOptionsPreventingCaching */ public function testGeneratorIsCreatedIfCacheIsNotConfigured($option) { $this->router->setOption($option, null); $this->loader->expects($this->once()) ->method('load')->with('routing.yml', null) ->willReturn(new RouteCollection()); $this->assertInstanceOf('Symfony\\Component\\Routing\\Generator\\UrlGenerator', $this->router->getGenerator()); } public function provideGeneratorOptionsPreventingCaching() { return [ ['cache_dir'], ['generator_cache_class'], ]; } public function testMatchRequestWithUrlMatcherInterface() { $matcher = $this->getMockBuilder('Symfony\Component\Routing\Matcher\UrlMatcherInterface')->getMock(); $matcher->expects($this->once())->method('match'); $p = new \ReflectionProperty($this->router, 'matcher'); $p->setAccessible(true); $p->setValue($this->router, $matcher); $this->router->matchRequest(Request::create('/')); } public function testMatchRequestWithRequestMatcherInterface() { $matcher = $this->getMockBuilder('Symfony\Component\Routing\Matcher\RequestMatcherInterface')->getMock(); $matcher->expects($this->once())->method('matchRequest'); $p = new \ReflectionProperty($this->router, 'matcher'); $p->setAccessible(true); $p->setValue($this->router, $matcher); $this->router->matchRequest(Request::create('/')); } } Loader/YamlFileLoaderTest.php000064400000020202150312232120012137 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Loader; use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Routing\Loader\YamlFileLoader; class YamlFileLoaderTest extends TestCase { public function testSupports() { $loader = new YamlFileLoader($this->getMockBuilder('Symfony\Component\Config\FileLocator')->getMock()); $this->assertTrue($loader->supports('foo.yml'), '->supports() returns true if the resource is loadable'); $this->assertTrue($loader->supports('foo.yaml'), '->supports() returns true if the resource is loadable'); $this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable'); $this->assertTrue($loader->supports('foo.yml', 'yaml'), '->supports() checks the resource type if specified'); $this->assertTrue($loader->supports('foo.yaml', 'yaml'), '->supports() checks the resource type if specified'); $this->assertFalse($loader->supports('foo.yml', 'foo'), '->supports() checks the resource type if specified'); } public function testLoadDoesNothingIfEmpty() { $loader = new YamlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $collection = $loader->load('empty.yml'); $this->assertEquals([], $collection->all()); $this->assertEquals([new FileResource(realpath(__DIR__.'/../Fixtures/empty.yml'))], $collection->getResources()); } /** * @dataProvider getPathsToInvalidFiles */ public function testLoadThrowsExceptionWithInvalidFile($filePath) { $this->expectException('InvalidArgumentException'); $loader = new YamlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $loader->load($filePath); } public function getPathsToInvalidFiles() { return [ ['nonvalid.yml'], ['nonvalid2.yml'], ['incomplete.yml'], ['nonvalidkeys.yml'], ['nonesense_resource_plus_path.yml'], ['nonesense_type_without_resource.yml'], ['bad_format.yml'], ]; } public function testLoadSpecialRouteName() { $loader = new YamlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $routeCollection = $loader->load('special_route_name.yml'); $route = $routeCollection->get('#$péß^a|'); $this->assertInstanceOf('Symfony\Component\Routing\Route', $route); $this->assertSame('/true', $route->getPath()); } public function testLoadWithRoute() { $loader = new YamlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $routeCollection = $loader->load('validpattern.yml'); $route = $routeCollection->get('blog_show'); $this->assertInstanceOf('Symfony\Component\Routing\Route', $route); $this->assertSame('/blog/{slug}', $route->getPath()); $this->assertSame('{locale}.example.com', $route->getHost()); $this->assertSame('MyBundle:Blog:show', $route->getDefault('_controller')); $this->assertSame('\w+', $route->getRequirement('locale')); $this->assertSame('RouteCompiler', $route->getOption('compiler_class')); $this->assertEquals(['GET', 'POST', 'PUT', 'OPTIONS'], $route->getMethods()); $this->assertEquals(['https'], $route->getSchemes()); $this->assertEquals('context.getMethod() == "GET"', $route->getCondition()); } public function testLoadWithResource() { $loader = new YamlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $routeCollection = $loader->load('validresource.yml'); $routes = $routeCollection->all(); $this->assertCount(2, $routes, 'Two routes are loaded'); $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes); foreach ($routes as $route) { $this->assertSame('/{foo}/blog/{slug}', $route->getPath()); $this->assertSame('123', $route->getDefault('foo')); $this->assertSame('\d+', $route->getRequirement('foo')); $this->assertSame('bar', $route->getOption('foo')); $this->assertSame('', $route->getHost()); $this->assertSame('context.getMethod() == "POST"', $route->getCondition()); } } public function testLoadRouteWithControllerAttribute() { $loader = new YamlFileLoader(new FileLocator([__DIR__.'/../Fixtures/controller'])); $routeCollection = $loader->load('routing.yml'); $route = $routeCollection->get('app_homepage'); $this->assertSame('AppBundle:Homepage:show', $route->getDefault('_controller')); } public function testLoadRouteWithoutControllerAttribute() { $loader = new YamlFileLoader(new FileLocator([__DIR__.'/../Fixtures/controller'])); $routeCollection = $loader->load('routing.yml'); $route = $routeCollection->get('app_logout'); $this->assertNull($route->getDefault('_controller')); } public function testLoadRouteWithControllerSetInDefaults() { $loader = new YamlFileLoader(new FileLocator([__DIR__.'/../Fixtures/controller'])); $routeCollection = $loader->load('routing.yml'); $route = $routeCollection->get('app_blog'); $this->assertSame('AppBundle:Blog:list', $route->getDefault('_controller')); } public function testOverrideControllerInDefaults() { $this->expectException('InvalidArgumentException'); $this->expectExceptionMessageMatches('/The routing file "[^"]*" must not specify both the "controller" key and the defaults key "_controller" for "app_blog"/'); $loader = new YamlFileLoader(new FileLocator([__DIR__.'/../Fixtures/controller'])); $loader->load('override_defaults.yml'); } /** * @dataProvider provideFilesImportingRoutesWithControllers */ public function testImportRouteWithController($file) { $loader = new YamlFileLoader(new FileLocator([__DIR__.'/../Fixtures/controller'])); $routeCollection = $loader->load($file); $route = $routeCollection->get('app_homepage'); $this->assertSame('FrameworkBundle:Template:template', $route->getDefault('_controller')); $route = $routeCollection->get('app_blog'); $this->assertSame('FrameworkBundle:Template:template', $route->getDefault('_controller')); $route = $routeCollection->get('app_logout'); $this->assertSame('FrameworkBundle:Template:template', $route->getDefault('_controller')); } public function provideFilesImportingRoutesWithControllers() { yield ['import_controller.yml']; yield ['import__controller.yml']; } public function testImportWithOverriddenController() { $this->expectException('InvalidArgumentException'); $this->expectExceptionMessageMatches('/The routing file "[^"]*" must not specify both the "controller" key and the defaults key "_controller" for "_static"/'); $loader = new YamlFileLoader(new FileLocator([__DIR__.'/../Fixtures/controller'])); $loader->load('import_override_defaults.yml'); } public function testImportRouteWithGlobMatchingSingleFile() { $loader = new YamlFileLoader(new FileLocator([__DIR__.'/../Fixtures/glob'])); $routeCollection = $loader->load('import_single.yml'); $route = $routeCollection->get('bar_route'); $this->assertSame('AppBundle:Bar:view', $route->getDefault('_controller')); } public function testImportRouteWithGlobMatchingMultipleFiles() { $loader = new YamlFileLoader(new FileLocator([__DIR__.'/../Fixtures/glob'])); $routeCollection = $loader->load('import_multiple.yml'); $route = $routeCollection->get('bar_route'); $this->assertSame('AppBundle:Bar:view', $route->getDefault('_controller')); $route = $routeCollection->get('baz_route'); $this->assertSame('AppBundle:Baz:view', $route->getDefault('_controller')); } } Loader/AnnotationClassLoaderTest.php000064400000031557150312232120013554 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Loader; use Symfony\Component\Routing\Annotation\Route; class AnnotationClassLoaderTest extends AbstractAnnotationLoaderTest { protected $loader; private $reader; protected function setUp() { parent::setUp(); $this->reader = $this->getReader(); $this->loader = $this->getClassLoader($this->reader); } public function testLoadMissingClass() { $this->expectException('InvalidArgumentException'); $this->loader->load('MissingClass'); } public function testLoadAbstractClass() { $this->expectException('InvalidArgumentException'); $this->loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\AbstractClass'); } /** * @dataProvider provideTestSupportsChecksResource */ public function testSupportsChecksResource($resource, $expectedSupports) { $this->assertSame($expectedSupports, $this->loader->supports($resource), '->supports() returns true if the resource is loadable'); } public function provideTestSupportsChecksResource() { return [ ['class', true], ['\fully\qualified\class\name', true], ['namespaced\class\without\leading\slash', true], ['ÿClassWithLegalSpecialCharacters', true], ['5', false], ['foo.foo', false], [null, false], ]; } public function testSupportsChecksTypeIfSpecified() { $this->assertTrue($this->loader->supports('class', 'annotation'), '->supports() checks the resource type if specified'); $this->assertFalse($this->loader->supports('class', 'foo'), '->supports() checks the resource type if specified'); } public function getLoadTests() { return [ [ 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass', ['name' => 'route1', 'path' => '/path'], ['arg2' => 'defaultValue2', 'arg3' => 'defaultValue3'], ], [ 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass', ['defaults' => ['arg2' => 'foo'], 'requirements' => ['arg3' => '\w+']], ['arg2' => 'defaultValue2', 'arg3' => 'defaultValue3'], ], [ 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass', ['options' => ['foo' => 'bar']], ['arg2' => 'defaultValue2', 'arg3' => 'defaultValue3'], ], [ 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass', ['schemes' => ['https'], 'methods' => ['GET']], ['arg2' => 'defaultValue2', 'arg3' => 'defaultValue3'], ], [ 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass', ['condition' => 'context.getMethod() == "GET"'], ['arg2' => 'defaultValue2', 'arg3' => 'defaultValue3'], ], ]; } /** * @dataProvider getLoadTests */ public function testLoad($className, $routeData = [], $methodArgs = []) { $routeData = array_replace([ 'name' => 'route', 'path' => '/', 'requirements' => [], 'options' => [], 'defaults' => [], 'schemes' => [], 'methods' => [], 'condition' => '', ], $routeData); $this->reader ->expects($this->once()) ->method('getMethodAnnotations') ->willReturn([$this->getAnnotatedRoute($routeData)]) ; $routeCollection = $this->loader->load($className); $route = $routeCollection->get($routeData['name']); $this->assertSame($routeData['path'], $route->getPath(), '->load preserves path annotation'); $this->assertCount( \count($routeData['requirements']), array_intersect_assoc($routeData['requirements'], $route->getRequirements()), '->load preserves requirements annotation' ); $this->assertCount( \count($routeData['options']), array_intersect_assoc($routeData['options'], $route->getOptions()), '->load preserves options annotation' ); $this->assertCount( \count($routeData['defaults']), $route->getDefaults(), '->load preserves defaults annotation' ); $this->assertEquals($routeData['schemes'], $route->getSchemes(), '->load preserves schemes annotation'); $this->assertEquals($routeData['methods'], $route->getMethods(), '->load preserves methods annotation'); $this->assertSame($routeData['condition'], $route->getCondition(), '->load preserves condition annotation'); } public function testClassRouteLoad() { $classRouteData = [ 'name' => 'prefix_', 'path' => '/prefix', 'schemes' => ['https'], 'methods' => ['GET'], ]; $methodRouteData = [ 'name' => 'route1', 'path' => '/path', 'schemes' => ['http'], 'methods' => ['POST', 'PUT'], ]; $this->reader ->expects($this->once()) ->method('getClassAnnotation') ->willReturn($this->getAnnotatedRoute($classRouteData)) ; $this->reader ->expects($this->once()) ->method('getMethodAnnotations') ->willReturn([$this->getAnnotatedRoute($methodRouteData)]) ; $routeCollection = $this->loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass'); $route = $routeCollection->get($classRouteData['name'].$methodRouteData['name']); $this->assertSame($classRouteData['path'].$methodRouteData['path'], $route->getPath(), '->load concatenates class and method route path'); $this->assertEquals(array_merge($classRouteData['schemes'], $methodRouteData['schemes']), $route->getSchemes(), '->load merges class and method route schemes'); $this->assertEquals(array_merge($classRouteData['methods'], $methodRouteData['methods']), $route->getMethods(), '->load merges class and method route methods'); } public function testInvokableClassRouteLoadWithMethodAnnotation() { $classRouteData = [ 'name' => 'route1', 'path' => '/', 'schemes' => ['https'], 'methods' => ['GET'], ]; $this->reader ->expects($this->exactly(1)) ->method('getClassAnnotations') ->willReturn([$this->getAnnotatedRoute($classRouteData)]) ; $this->reader ->expects($this->once()) ->method('getMethodAnnotations') ->willReturn([]) ; $routeCollection = $this->loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BazClass'); $route = $routeCollection->get($classRouteData['name']); $this->assertSame($classRouteData['path'], $route->getPath(), '->load preserves class route path'); $this->assertEquals($classRouteData['schemes'], $route->getSchemes(), '->load preserves class route schemes'); $this->assertEquals($classRouteData['methods'], $route->getMethods(), '->load preserves class route methods'); } public function testInvokableClassRouteLoadWithClassAnnotation() { $classRouteData = [ 'name' => 'route1', 'path' => '/', 'schemes' => ['https'], 'methods' => ['GET'], ]; $this->reader ->expects($this->exactly(1)) ->method('getClassAnnotation') ->willReturn($this->getAnnotatedRoute($classRouteData)) ; $this->reader ->expects($this->exactly(1)) ->method('getClassAnnotations') ->willReturn([$this->getAnnotatedRoute($classRouteData)]) ; $this->reader ->expects($this->once()) ->method('getMethodAnnotations') ->willReturn([]) ; $routeCollection = $this->loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BazClass'); $route = $routeCollection->get($classRouteData['name']); $this->assertSame($classRouteData['path'], $route->getPath(), '->load preserves class route path'); $this->assertEquals($classRouteData['schemes'], $route->getSchemes(), '->load preserves class route schemes'); $this->assertEquals($classRouteData['methods'], $route->getMethods(), '->load preserves class route methods'); } public function testInvokableClassMultipleRouteLoad() { $classRouteData1 = [ 'name' => 'route1', 'path' => '/1', 'schemes' => ['https'], 'methods' => ['GET'], ]; $classRouteData2 = [ 'name' => 'route2', 'path' => '/2', 'schemes' => ['https'], 'methods' => ['GET'], ]; $this->reader ->expects($this->exactly(1)) ->method('getClassAnnotations') ->willReturn([$this->getAnnotatedRoute($classRouteData1), $this->getAnnotatedRoute($classRouteData2)]) ; $this->reader ->expects($this->once()) ->method('getMethodAnnotations') ->willReturn([]) ; $routeCollection = $this->loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BazClass'); $route = $routeCollection->get($classRouteData1['name']); $this->assertSame($classRouteData1['path'], $route->getPath(), '->load preserves class route path'); $this->assertEquals($classRouteData1['schemes'], $route->getSchemes(), '->load preserves class route schemes'); $this->assertEquals($classRouteData1['methods'], $route->getMethods(), '->load preserves class route methods'); $route = $routeCollection->get($classRouteData2['name']); $this->assertSame($classRouteData2['path'], $route->getPath(), '->load preserves class route path'); $this->assertEquals($classRouteData2['schemes'], $route->getSchemes(), '->load preserves class route schemes'); $this->assertEquals($classRouteData2['methods'], $route->getMethods(), '->load preserves class route methods'); } public function testInvokableClassWithMethodRouteLoad() { $classRouteData = [ 'name' => 'route1', 'path' => '/prefix', 'schemes' => ['https'], 'methods' => ['GET'], ]; $methodRouteData = [ 'name' => 'route2', 'path' => '/path', 'schemes' => ['http'], 'methods' => ['POST', 'PUT'], ]; $this->reader ->expects($this->once()) ->method('getClassAnnotation') ->willReturn($this->getAnnotatedRoute($classRouteData)) ; $this->reader ->expects($this->once()) ->method('getMethodAnnotations') ->willReturn([$this->getAnnotatedRoute($methodRouteData)]) ; $routeCollection = $this->loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BazClass'); $route = $routeCollection->get($classRouteData['name']); $this->assertNull($route, '->load ignores class route'); $route = $routeCollection->get($classRouteData['name'].$methodRouteData['name']); $this->assertSame($classRouteData['path'].$methodRouteData['path'], $route->getPath(), '->load concatenates class and method route path'); $this->assertEquals(array_merge($classRouteData['schemes'], $methodRouteData['schemes']), $route->getSchemes(), '->load merges class and method route schemes'); $this->assertEquals(array_merge($classRouteData['methods'], $methodRouteData['methods']), $route->getMethods(), '->load merges class and method route methods'); } /** * @requires function mb_strtolower */ public function testDefaultRouteName() { $methodRouteData = [ 'name' => null, ]; $this->reader ->expects($this->once()) ->method('getMethodAnnotations') ->willReturn([$this->getAnnotatedRoute($methodRouteData)]) ; $routeCollection = $this->loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\EncodingClass'); $defaultName = array_keys($routeCollection->all())[0]; $this->assertSame($defaultName, 'symfony_component_routing_tests_fixtures_annotatedclasses_encodingclass_routeàction'); } private function getAnnotatedRoute($data) { return new Route($data); } } Loader/PhpFileLoaderTest.php000064400000012641150312232120011774 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Loader; use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Routing\Loader\PhpFileLoader; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; class PhpFileLoaderTest extends TestCase { public function testSupports() { $loader = new PhpFileLoader($this->getMockBuilder('Symfony\Component\Config\FileLocator')->getMock()); $this->assertTrue($loader->supports('foo.php'), '->supports() returns true if the resource is loadable'); $this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable'); $this->assertTrue($loader->supports('foo.php', 'php'), '->supports() checks the resource type if specified'); $this->assertFalse($loader->supports('foo.php', 'foo'), '->supports() checks the resource type if specified'); } public function testLoadWithRoute() { $loader = new PhpFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $routeCollection = $loader->load('validpattern.php'); $routes = $routeCollection->all(); $this->assertCount(1, $routes, 'One route is loaded'); $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes); foreach ($routes as $route) { $this->assertSame('/blog/{slug}', $route->getPath()); $this->assertSame('MyBlogBundle:Blog:show', $route->getDefault('_controller')); $this->assertSame('{locale}.example.com', $route->getHost()); $this->assertSame('RouteCompiler', $route->getOption('compiler_class')); $this->assertEquals(['GET', 'POST', 'PUT', 'OPTIONS'], $route->getMethods()); $this->assertEquals(['https'], $route->getSchemes()); } } public function testLoadWithImport() { $loader = new PhpFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $routeCollection = $loader->load('validresource.php'); $routes = $routeCollection->all(); $this->assertCount(1, $routes, 'One route is loaded'); $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes); foreach ($routes as $route) { $this->assertSame('/prefix/blog/{slug}', $route->getPath()); $this->assertSame('MyBlogBundle:Blog:show', $route->getDefault('_controller')); $this->assertSame('{locale}.example.com', $route->getHost()); $this->assertSame('RouteCompiler', $route->getOption('compiler_class')); $this->assertEquals(['GET', 'POST', 'PUT', 'OPTIONS'], $route->getMethods()); $this->assertEquals(['https'], $route->getSchemes()); } } public function testThatDefiningVariableInConfigFileHasNoSideEffects() { $locator = new FileLocator([__DIR__.'/../Fixtures']); $loader = new PhpFileLoader($locator); $routeCollection = $loader->load('with_define_path_variable.php'); $resources = $routeCollection->getResources(); $this->assertCount(1, $resources); $this->assertContainsOnly('Symfony\Component\Config\Resource\ResourceInterface', $resources); $fileResource = reset($resources); $this->assertSame( realpath($locator->locate('with_define_path_variable.php')), (string) $fileResource ); } public function testRoutingConfigurator() { $locator = new FileLocator([__DIR__.'/../Fixtures']); $loader = new PhpFileLoader($locator); $routeCollection = $loader->load('php_dsl.php'); $expectedCollection = new RouteCollection(); $expectedCollection->add('foo', (new Route('/foo')) ->setOptions(['utf8' => true]) ->setCondition('abc') ); $expectedCollection->add('buz', (new Route('/zub')) ->setDefaults(['_controller' => 'foo:act']) ); $expectedCollection->add('c_bar', (new Route('/sub/pub/bar')) ->setRequirements(['id' => '\d+']) ); $expectedCollection->add('c_pub_buz', (new Route('/sub/pub/buz')) ->setHost('host') ->setRequirements(['id' => '\d+']) ); $expectedCollection->add('ouf', (new Route('/ouf')) ->setSchemes(['https']) ->setMethods(['GET']) ->setDefaults(['id' => 0]) ); $expectedCollection->addResource(new FileResource(realpath(__DIR__.'/../Fixtures/php_dsl_sub.php'))); $expectedCollection->addResource(new FileResource(realpath(__DIR__.'/../Fixtures/php_dsl.php'))); $this->assertEquals($expectedCollection, $routeCollection); } public function testRoutingConfiguratorCanImportGlobPatterns() { $locator = new FileLocator([__DIR__.'/../Fixtures/glob']); $loader = new PhpFileLoader($locator); $routeCollection = $loader->load('php_dsl.php'); $route = $routeCollection->get('bar_route'); $this->assertSame('AppBundle:Bar:view', $route->getDefault('_controller')); $route = $routeCollection->get('baz_route'); $this->assertSame('AppBundle:Baz:view', $route->getDefault('_controller')); } } Loader/ClosureLoaderTest.php000064400000002727150312232120012065 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Loader; use PHPUnit\Framework\TestCase; use Symfony\Component\Routing\Loader\ClosureLoader; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; class ClosureLoaderTest extends TestCase { public function testSupports() { $loader = new ClosureLoader(); $closure = function () {}; $this->assertTrue($loader->supports($closure), '->supports() returns true if the resource is loadable'); $this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable'); $this->assertTrue($loader->supports($closure, 'closure'), '->supports() checks the resource type if specified'); $this->assertFalse($loader->supports($closure, 'foo'), '->supports() checks the resource type if specified'); } public function testLoad() { $loader = new ClosureLoader(); $route = new Route('/'); $routes = $loader->load(function () use ($route) { $routes = new RouteCollection(); $routes->add('foo', $route); return $routes; }); $this->assertEquals($route, $routes->get('foo'), '->load() loads a \Closure resource'); } } Loader/DirectoryLoaderTest.php000064400000004507150312232120012413 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Loader; use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\Loader\LoaderResolver; use Symfony\Component\Routing\Loader\AnnotationFileLoader; use Symfony\Component\Routing\Loader\DirectoryLoader; use Symfony\Component\Routing\Loader\YamlFileLoader; use Symfony\Component\Routing\RouteCollection; class DirectoryLoaderTest extends AbstractAnnotationLoaderTest { private $loader; private $reader; protected function setUp() { parent::setUp(); $locator = new FileLocator(); $this->reader = $this->getReader(); $this->loader = new DirectoryLoader($locator); $resolver = new LoaderResolver([ new YamlFileLoader($locator), new AnnotationFileLoader($locator, $this->getClassLoader($this->reader)), $this->loader, ]); $this->loader->setResolver($resolver); } public function testLoadDirectory() { $collection = $this->loader->load(__DIR__.'/../Fixtures/directory', 'directory'); $this->verifyCollection($collection); } public function testImportDirectory() { $collection = $this->loader->load(__DIR__.'/../Fixtures/directory_import', 'directory'); $this->verifyCollection($collection); } private function verifyCollection(RouteCollection $collection) { $routes = $collection->all(); $this->assertCount(3, $routes, 'Three routes are loaded'); $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes); for ($i = 1; $i <= 3; ++$i) { $this->assertSame('/route/'.$i, $routes['route'.$i]->getPath()); } } public function testSupports() { $fixturesDir = __DIR__.'/../Fixtures'; $this->assertFalse($this->loader->supports($fixturesDir), '->supports(*) returns false'); $this->assertTrue($this->loader->supports($fixturesDir, 'directory'), '->supports(*, "directory") returns true'); $this->assertFalse($this->loader->supports($fixturesDir, 'foo'), '->supports(*, "foo") returns false'); } } Loader/AnnotationDirectoryLoaderTest.php000064400000006752150312232120014452 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Loader; use Symfony\Component\Config\FileLocator; use Symfony\Component\Routing\Loader\AnnotationDirectoryLoader; class AnnotationDirectoryLoaderTest extends AbstractAnnotationLoaderTest { protected $loader; protected $reader; protected function setUp() { parent::setUp(); $this->reader = $this->getReader(); $this->loader = new AnnotationDirectoryLoader(new FileLocator(), $this->getClassLoader($this->reader)); } public function testLoad() { $this->reader->expects($this->exactly(4))->method('getClassAnnotation'); $this->reader ->expects($this->any()) ->method('getMethodAnnotations') ->willReturn([]) ; $this->reader ->expects($this->any()) ->method('getClassAnnotations') ->willReturn([]) ; $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses'); } public function testLoadIgnoresHiddenDirectories() { $this->expectAnnotationsToBeReadFrom([ 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass', 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BazClass', 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\FooClass', 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\EncodingClass', ]); $this->reader ->expects($this->any()) ->method('getMethodAnnotations') ->willReturn([]) ; $this->reader ->expects($this->any()) ->method('getClassAnnotations') ->willReturn([]) ; $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses'); } public function testSupports() { $fixturesDir = __DIR__.'/../Fixtures'; $this->assertTrue($this->loader->supports($fixturesDir), '->supports() returns true if the resource is loadable'); $this->assertFalse($this->loader->supports('foo.foo'), '->supports() returns true if the resource is loadable'); $this->assertTrue($this->loader->supports($fixturesDir, 'annotation'), '->supports() checks the resource type if specified'); $this->assertFalse($this->loader->supports($fixturesDir, 'foo'), '->supports() checks the resource type if specified'); } public function testItSupportsAnyAnnotation() { $this->assertTrue($this->loader->supports(__DIR__.'/../Fixtures/even-with-not-existing-folder', 'annotation')); } public function testLoadFileIfLocatedResourceIsFile() { $this->reader->expects($this->exactly(1))->method('getClassAnnotation'); $this->reader ->expects($this->any()) ->method('getMethodAnnotations') ->willReturn([]) ; $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/FooClass.php'); } private function expectAnnotationsToBeReadFrom(array $classes) { $this->reader->expects($this->exactly(\count($classes))) ->method('getClassAnnotation') ->with($this->callback(function (\ReflectionClass $class) use ($classes) { return \in_array($class->getName(), $classes); })); } } Loader/GlobFileLoaderTest.php000064400000002717150312232120012133 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Loader; use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\Resource\GlobResource; use Symfony\Component\Routing\Loader\GlobFileLoader; use Symfony\Component\Routing\RouteCollection; class GlobFileLoaderTest extends TestCase { public function testSupports() { $loader = new GlobFileLoader(new FileLocator()); $this->assertTrue($loader->supports('any-path', 'glob'), '->supports() returns true if the resource has the glob type'); $this->assertFalse($loader->supports('any-path'), '->supports() returns false if the resource is not of glob type'); } public function testLoadAddsTheGlobResourceToTheContainer() { $loader = new GlobFileLoaderWithoutImport(new FileLocator()); $collection = $loader->load(__DIR__.'/../Fixtures/directory/*.yml'); $this->assertEquals(new GlobResource(__DIR__.'/../Fixtures/directory', '/*.yml', false), $collection->getResources()[0]); } } class GlobFileLoaderWithoutImport extends GlobFileLoader { public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null) { return new RouteCollection(); } } Loader/AbstractAnnotationLoaderTest.php000064400000001475150312232120014246 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Loader; use PHPUnit\Framework\TestCase; abstract class AbstractAnnotationLoaderTest extends TestCase { public function getReader() { return $this->getMockBuilder('Doctrine\Common\Annotations\Reader') ->disableOriginalConstructor() ->getMock() ; } public function getClassLoader($reader) { return $this->getMockBuilder('Symfony\Component\Routing\Loader\AnnotationClassLoader') ->setConstructorArgs([$reader]) ->getMockForAbstractClass() ; } } Loader/AnnotationFileLoaderTest.php000064400000006254150312232120013362 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Loader; use Symfony\Component\Config\FileLocator; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Loader\AnnotationFileLoader; class AnnotationFileLoaderTest extends AbstractAnnotationLoaderTest { protected $loader; protected $reader; protected function setUp() { parent::setUp(); $this->reader = $this->getReader(); $this->loader = new AnnotationFileLoader(new FileLocator(), $this->getClassLoader($this->reader)); } public function testLoad() { $this->reader->expects($this->once())->method('getClassAnnotation'); $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/FooClass.php'); } public function testLoadTraitWithClassConstant() { $this->reader->expects($this->never())->method('getClassAnnotation'); $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/FooTrait.php'); } public function testLoadFileWithoutStartTag() { $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage('Did you forgot to add the "loader->load(__DIR__.'/../Fixtures/OtherAnnotatedClasses/NoStartTagClass.php'); } /** * @requires PHP 5.6 */ public function testLoadVariadic() { $route = new Route(['path' => '/path/to/{id}']); $this->reader->expects($this->once())->method('getClassAnnotation'); $this->reader->expects($this->once())->method('getMethodAnnotations') ->willReturn([$route]); $this->loader->load(__DIR__.'/../Fixtures/OtherAnnotatedClasses/VariadicClass.php'); } /** * @requires PHP 7.0 */ public function testLoadAnonymousClass() { $this->reader->expects($this->never())->method('getClassAnnotation'); $this->reader->expects($this->never())->method('getMethodAnnotations'); $this->loader->load(__DIR__.'/../Fixtures/OtherAnnotatedClasses/AnonymousClassInTrait.php'); } public function testLoadAbstractClass() { $this->reader->expects($this->never())->method('getClassAnnotation'); $this->reader->expects($this->never())->method('getMethodAnnotations'); $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/AbstractClass.php'); } public function testSupports() { $fixture = __DIR__.'/../Fixtures/annotated.php'; $this->assertTrue($this->loader->supports($fixture), '->supports() returns true if the resource is loadable'); $this->assertFalse($this->loader->supports('foo.foo'), '->supports() returns true if the resource is loadable'); $this->assertTrue($this->loader->supports($fixture, 'annotation'), '->supports() checks the resource type if specified'); $this->assertFalse($this->loader->supports($fixture, 'foo'), '->supports() checks the resource type if specified'); } } Loader/ObjectRouteLoaderTest.php000064400000006164150312232120012675 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Loader; use PHPUnit\Framework\TestCase; use Symfony\Component\Routing\Loader\ObjectRouteLoader; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; class ObjectRouteLoaderTest extends TestCase { public function testLoadCallsServiceAndReturnsCollection() { $loader = new ObjectRouteLoaderForTest(); // create a basic collection that will be returned $collection = new RouteCollection(); $collection->add('foo', new Route('/foo')); $loader->loaderMap = [ 'my_route_provider_service' => new RouteService($collection), ]; $actualRoutes = $loader->load( 'my_route_provider_service:loadRoutes', 'service' ); $this->assertSame($collection, $actualRoutes); // the service file should be listed as a resource $this->assertNotEmpty($actualRoutes->getResources()); } /** * @dataProvider getBadResourceStrings */ public function testExceptionWithoutSyntax($resourceString) { $this->expectException('InvalidArgumentException'); $loader = new ObjectRouteLoaderForTest(); $loader->load($resourceString); } public function getBadResourceStrings() { return [ ['Foo'], ['Bar::baz'], ['Foo:Bar:baz'], ]; } public function testExceptionOnNoObjectReturned() { $this->expectException('LogicException'); $loader = new ObjectRouteLoaderForTest(); $loader->loaderMap = ['my_service' => 'NOT_AN_OBJECT']; $loader->load('my_service:method'); } public function testExceptionOnBadMethod() { $this->expectException('BadMethodCallException'); $loader = new ObjectRouteLoaderForTest(); $loader->loaderMap = ['my_service' => new \stdClass()]; $loader->load('my_service:method'); } public function testExceptionOnMethodNotReturningCollection() { $this->expectException('LogicException'); $service = $this->getMockBuilder('stdClass') ->setMethods(['loadRoutes']) ->getMock(); $service->expects($this->once()) ->method('loadRoutes') ->willReturn('NOT_A_COLLECTION'); $loader = new ObjectRouteLoaderForTest(); $loader->loaderMap = ['my_service' => $service]; $loader->load('my_service:loadRoutes'); } } class ObjectRouteLoaderForTest extends ObjectRouteLoader { public $loaderMap = []; protected function getServiceObject($id) { return isset($this->loaderMap[$id]) ? $this->loaderMap[$id] : null; } } class RouteService { private $collection; public function __construct($collection) { $this->collection = $collection; } public function loadRoutes() { return $this->collection; } } Loader/XmlFileLoaderTest.php000064400000035162150312232120012010 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Loader; use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; use Symfony\Component\Routing\Loader\XmlFileLoader; use Symfony\Component\Routing\Tests\Fixtures\CustomXmlFileLoader; class XmlFileLoaderTest extends TestCase { public function testSupports() { $loader = new XmlFileLoader($this->getMockBuilder('Symfony\Component\Config\FileLocator')->getMock()); $this->assertTrue($loader->supports('foo.xml'), '->supports() returns true if the resource is loadable'); $this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable'); $this->assertTrue($loader->supports('foo.xml', 'xml'), '->supports() checks the resource type if specified'); $this->assertFalse($loader->supports('foo.xml', 'foo'), '->supports() checks the resource type if specified'); } public function testLoadWithRoute() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $routeCollection = $loader->load('validpattern.xml'); $route = $routeCollection->get('blog_show'); $this->assertInstanceOf('Symfony\Component\Routing\Route', $route); $this->assertSame('/blog/{slug}', $route->getPath()); $this->assertSame('{locale}.example.com', $route->getHost()); $this->assertSame('MyBundle:Blog:show', $route->getDefault('_controller')); $this->assertSame('\w+', $route->getRequirement('locale')); $this->assertSame('RouteCompiler', $route->getOption('compiler_class')); $this->assertEquals(['GET', 'POST', 'PUT', 'OPTIONS'], $route->getMethods()); $this->assertEquals(['https'], $route->getSchemes()); $this->assertEquals('context.getMethod() == "GET"', $route->getCondition()); } public function testLoadWithNamespacePrefix() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $routeCollection = $loader->load('namespaceprefix.xml'); $this->assertCount(1, $routeCollection->all(), 'One route is loaded'); $route = $routeCollection->get('blog_show'); $this->assertSame('/blog/{slug}', $route->getPath()); $this->assertSame('{_locale}.example.com', $route->getHost()); $this->assertSame('MyBundle:Blog:show', $route->getDefault('_controller')); $this->assertSame('\w+', $route->getRequirement('slug')); $this->assertSame('en|fr|de', $route->getRequirement('_locale')); $this->assertNull($route->getDefault('slug')); $this->assertSame('RouteCompiler', $route->getOption('compiler_class')); $this->assertSame(1, $route->getDefault('page')); } public function testLoadWithImport() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $routeCollection = $loader->load('validresource.xml'); $routes = $routeCollection->all(); $this->assertCount(2, $routes, 'Two routes are loaded'); $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes); foreach ($routes as $route) { $this->assertSame('/{foo}/blog/{slug}', $route->getPath()); $this->assertSame('123', $route->getDefault('foo')); $this->assertSame('\d+', $route->getRequirement('foo')); $this->assertSame('bar', $route->getOption('foo')); $this->assertSame('', $route->getHost()); $this->assertSame('context.getMethod() == "POST"', $route->getCondition()); } } public function testUtf8Route() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures/localized'])); $routeCollection = $loader->load('utf8.xml'); $routes = $routeCollection->all(); $this->assertCount(2, $routes, 'Two routes are loaded'); $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes); $utf8Route = $routeCollection->get('app_utf8'); $this->assertSame('/utf8', $utf8Route->getPath()); $this->assertTrue($utf8Route->getOption('utf8'), 'Must be utf8'); $noUtf8Route = $routeCollection->get('app_no_utf8'); $this->assertSame('/no-utf8', $noUtf8Route->getPath()); $this->assertFalse($noUtf8Route->getOption('utf8'), 'Must not be utf8'); } /** * @dataProvider getPathsToInvalidFiles */ public function testLoadThrowsExceptionWithInvalidFile($filePath) { $this->expectException('InvalidArgumentException'); $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $loader->load($filePath); } /** * @dataProvider getPathsToInvalidFiles */ public function testLoadThrowsExceptionWithInvalidFileEvenWithoutSchemaValidation($filePath) { $this->expectException('InvalidArgumentException'); $loader = new CustomXmlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $loader->load($filePath); } public function getPathsToInvalidFiles() { return [['nonvalidnode.xml'], ['nonvalidroute.xml'], ['nonvalid.xml'], ['missing_id.xml'], ['missing_path.xml']]; } public function testDocTypeIsNotAllowed() { $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage('Document types are not allowed.'); $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $loader->load('withdoctype.xml'); } public function testNullValues() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $routeCollection = $loader->load('null_values.xml'); $route = $routeCollection->get('blog_show'); $this->assertTrue($route->hasDefault('foo')); $this->assertNull($route->getDefault('foo')); $this->assertTrue($route->hasDefault('bar')); $this->assertNull($route->getDefault('bar')); $this->assertEquals('foo', $route->getDefault('foobar')); $this->assertEquals('bar', $route->getDefault('baz')); } public function testScalarDataTypeDefaults() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $routeCollection = $loader->load('scalar_defaults.xml'); $route = $routeCollection->get('blog'); $this->assertSame( [ '_controller' => 'AcmeBlogBundle:Blog:index', 'slug' => null, 'published' => true, 'page' => 1, 'price' => 3.5, 'archived' => false, 'free' => true, 'locked' => false, 'foo' => null, 'bar' => null, ], $route->getDefaults() ); } public function testListDefaults() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $routeCollection = $loader->load('list_defaults.xml'); $route = $routeCollection->get('blog'); $this->assertSame( [ '_controller' => 'AcmeBlogBundle:Blog:index', 'values' => [true, 1, 3.5, 'foo'], ], $route->getDefaults() ); } public function testListInListDefaults() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $routeCollection = $loader->load('list_in_list_defaults.xml'); $route = $routeCollection->get('blog'); $this->assertSame( [ '_controller' => 'AcmeBlogBundle:Blog:index', 'values' => [[true, 1, 3.5, 'foo']], ], $route->getDefaults() ); } public function testListInMapDefaults() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $routeCollection = $loader->load('list_in_map_defaults.xml'); $route = $routeCollection->get('blog'); $this->assertSame( [ '_controller' => 'AcmeBlogBundle:Blog:index', 'values' => ['list' => [true, 1, 3.5, 'foo']], ], $route->getDefaults() ); } public function testMapDefaults() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $routeCollection = $loader->load('map_defaults.xml'); $route = $routeCollection->get('blog'); $this->assertSame( [ '_controller' => 'AcmeBlogBundle:Blog:index', 'values' => [ 'public' => true, 'page' => 1, 'price' => 3.5, 'title' => 'foo', ], ], $route->getDefaults() ); } public function testMapInListDefaults() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $routeCollection = $loader->load('map_in_list_defaults.xml'); $route = $routeCollection->get('blog'); $this->assertSame( [ '_controller' => 'AcmeBlogBundle:Blog:index', 'values' => [[ 'public' => true, 'page' => 1, 'price' => 3.5, 'title' => 'foo', ]], ], $route->getDefaults() ); } public function testMapInMapDefaults() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $routeCollection = $loader->load('map_in_map_defaults.xml'); $route = $routeCollection->get('blog'); $this->assertSame( [ '_controller' => 'AcmeBlogBundle:Blog:index', 'values' => ['map' => [ 'public' => true, 'page' => 1, 'price' => 3.5, 'title' => 'foo', ]], ], $route->getDefaults() ); } public function testNullValuesInList() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $routeCollection = $loader->load('list_null_values.xml'); $route = $routeCollection->get('blog'); $this->assertSame([null, null, null, null, null, null], $route->getDefault('list')); } public function testNullValuesInMap() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); $routeCollection = $loader->load('map_null_values.xml'); $route = $routeCollection->get('blog'); $this->assertSame( [ 'boolean' => null, 'integer' => null, 'float' => null, 'string' => null, 'list' => null, 'map' => null, ], $route->getDefault('map') ); } public function testLoadRouteWithControllerAttribute() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures/controller'])); $routeCollection = $loader->load('routing.xml'); $route = $routeCollection->get('app_homepage'); $this->assertSame('AppBundle:Homepage:show', $route->getDefault('_controller')); } public function testLoadRouteWithoutControllerAttribute() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures/controller'])); $routeCollection = $loader->load('routing.xml'); $route = $routeCollection->get('app_logout'); $this->assertNull($route->getDefault('_controller')); } public function testLoadRouteWithControllerSetInDefaults() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures/controller'])); $routeCollection = $loader->load('routing.xml'); $route = $routeCollection->get('app_blog'); $this->assertSame('AppBundle:Blog:list', $route->getDefault('_controller')); } public function testOverrideControllerInDefaults() { $this->expectException('InvalidArgumentException'); $this->expectExceptionMessageMatches('/The routing file "[^"]*" must not specify both the "controller" attribute and the defaults key "_controller" for "app_blog"/'); $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures/controller'])); $loader->load('override_defaults.xml'); } /** * @dataProvider provideFilesImportingRoutesWithControllers */ public function testImportRouteWithController($file) { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures/controller'])); $routeCollection = $loader->load($file); $route = $routeCollection->get('app_homepage'); $this->assertSame('FrameworkBundle:Template:template', $route->getDefault('_controller')); $route = $routeCollection->get('app_blog'); $this->assertSame('FrameworkBundle:Template:template', $route->getDefault('_controller')); $route = $routeCollection->get('app_logout'); $this->assertSame('FrameworkBundle:Template:template', $route->getDefault('_controller')); } public function provideFilesImportingRoutesWithControllers() { yield ['import_controller.xml']; yield ['import__controller.xml']; } public function testImportWithOverriddenController() { $this->expectException('InvalidArgumentException'); $this->expectExceptionMessageMatches('/The routing file "[^"]*" must not specify both the "controller" attribute and the defaults key "_controller" for the "import" tag/'); $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures/controller'])); $loader->load('import_override_defaults.xml'); } public function testImportRouteWithGlobMatchingSingleFile() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures/glob'])); $routeCollection = $loader->load('import_single.xml'); $route = $routeCollection->get('bar_route'); $this->assertSame('AppBundle:Bar:view', $route->getDefault('_controller')); } public function testImportRouteWithGlobMatchingMultipleFiles() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures/glob'])); $routeCollection = $loader->load('import_multiple.xml'); $route = $routeCollection->get('bar_route'); $this->assertSame('AppBundle:Bar:view', $route->getDefault('_controller')); $route = $routeCollection->get('baz_route'); $this->assertSame('AppBundle:Baz:view', $route->getDefault('_controller')); } } CompiledRouteTest.php000064400000002056150312232120010662 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests; use PHPUnit\Framework\TestCase; use Symfony\Component\Routing\CompiledRoute; class CompiledRouteTest extends TestCase { public function testAccessors() { $compiled = new CompiledRoute('prefix', 'regex', ['tokens'], [], null, [], [], ['variables']); $this->assertEquals('prefix', $compiled->getStaticPrefix(), '__construct() takes a static prefix as its second argument'); $this->assertEquals('regex', $compiled->getRegex(), '__construct() takes a regexp as its third argument'); $this->assertEquals(['tokens'], $compiled->getTokens(), '__construct() takes an array of tokens as its fourth argument'); $this->assertEquals(['variables'], $compiled->getVariables(), '__construct() takes an array of variables as its ninth argument'); } } RouteCollectionTest.php000064400000033123150312232120011220 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests; use PHPUnit\Framework\TestCase; use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; class RouteCollectionTest extends TestCase { public function testRoute() { $collection = new RouteCollection(); $route = new Route('/foo'); $collection->add('foo', $route); $this->assertEquals(['foo' => $route], $collection->all(), '->add() adds a route'); $this->assertEquals($route, $collection->get('foo'), '->get() returns a route by name'); $this->assertNull($collection->get('bar'), '->get() returns null if a route does not exist'); } public function testOverriddenRoute() { $collection = new RouteCollection(); $collection->add('foo', new Route('/foo')); $collection->add('foo', new Route('/foo1')); $this->assertEquals('/foo1', $collection->get('foo')->getPath()); } public function testDeepOverriddenRoute() { $collection = new RouteCollection(); $collection->add('foo', new Route('/foo')); $collection1 = new RouteCollection(); $collection1->add('foo', new Route('/foo1')); $collection2 = new RouteCollection(); $collection2->add('foo', new Route('/foo2')); $collection1->addCollection($collection2); $collection->addCollection($collection1); $this->assertEquals('/foo2', $collection1->get('foo')->getPath()); $this->assertEquals('/foo2', $collection->get('foo')->getPath()); } public function testIterator() { $collection = new RouteCollection(); $collection->add('foo', new Route('/foo')); $collection1 = new RouteCollection(); $collection1->add('bar', $bar = new Route('/bar')); $collection1->add('foo', $foo = new Route('/foo-new')); $collection->addCollection($collection1); $collection->add('last', $last = new Route('/last')); $this->assertInstanceOf('\ArrayIterator', $collection->getIterator()); $this->assertSame(['bar' => $bar, 'foo' => $foo, 'last' => $last], $collection->getIterator()->getArrayCopy()); } public function testCount() { $collection = new RouteCollection(); $collection->add('foo', new Route('/foo')); $collection1 = new RouteCollection(); $collection1->add('bar', new Route('/bar')); $collection->addCollection($collection1); $this->assertCount(2, $collection); } public function testAddCollection() { $collection = new RouteCollection(); $collection->add('foo', new Route('/foo')); $collection1 = new RouteCollection(); $collection1->add('bar', $bar = new Route('/bar')); $collection1->add('foo', $foo = new Route('/foo-new')); $collection2 = new RouteCollection(); $collection2->add('grandchild', $grandchild = new Route('/grandchild')); $collection1->addCollection($collection2); $collection->addCollection($collection1); $collection->add('last', $last = new Route('/last')); $this->assertSame(['bar' => $bar, 'foo' => $foo, 'grandchild' => $grandchild, 'last' => $last], $collection->all(), '->addCollection() imports routes of another collection, overrides if necessary and adds them at the end'); } public function testAddCollectionWithResources() { $collection = new RouteCollection(); $collection->addResource($foo = new FileResource(__DIR__.'/Fixtures/foo.xml')); $collection1 = new RouteCollection(); $collection1->addResource($foo1 = new FileResource(__DIR__.'/Fixtures/foo1.xml')); $collection->addCollection($collection1); $this->assertEquals([$foo, $foo1], $collection->getResources(), '->addCollection() merges resources'); } public function testAddDefaultsAndRequirementsAndOptions() { $collection = new RouteCollection(); $collection->add('foo', new Route('/{placeholder}')); $collection1 = new RouteCollection(); $collection1->add('bar', new Route('/{placeholder}', ['_controller' => 'fixed', 'placeholder' => 'default'], ['placeholder' => '.+'], ['option' => 'value']) ); $collection->addCollection($collection1); $collection->addDefaults(['placeholder' => 'new-default']); $this->assertEquals(['placeholder' => 'new-default'], $collection->get('foo')->getDefaults(), '->addDefaults() adds defaults to all routes'); $this->assertEquals(['_controller' => 'fixed', 'placeholder' => 'new-default'], $collection->get('bar')->getDefaults(), '->addDefaults() adds defaults to all routes and overwrites existing ones'); $collection->addRequirements(['placeholder' => '\d+']); $this->assertEquals(['placeholder' => '\d+'], $collection->get('foo')->getRequirements(), '->addRequirements() adds requirements to all routes'); $this->assertEquals(['placeholder' => '\d+'], $collection->get('bar')->getRequirements(), '->addRequirements() adds requirements to all routes and overwrites existing ones'); $collection->addOptions(['option' => 'new-value']); $this->assertEquals( ['option' => 'new-value', 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler'], $collection->get('bar')->getOptions(), '->addOptions() adds options to all routes and overwrites existing ones' ); } public function testAddPrefix() { $collection = new RouteCollection(); $collection->add('foo', $foo = new Route('/foo')); $collection2 = new RouteCollection(); $collection2->add('bar', $bar = new Route('/bar')); $collection->addCollection($collection2); $collection->addPrefix(' / '); $this->assertSame('/foo', $collection->get('foo')->getPath(), '->addPrefix() trims the prefix and a single slash has no effect'); $collection->addPrefix('/{admin}', ['admin' => 'admin'], ['admin' => '\d+']); $this->assertEquals('/{admin}/foo', $collection->get('foo')->getPath(), '->addPrefix() adds a prefix to all routes'); $this->assertEquals('/{admin}/bar', $collection->get('bar')->getPath(), '->addPrefix() adds a prefix to all routes'); $this->assertEquals(['admin' => 'admin'], $collection->get('foo')->getDefaults(), '->addPrefix() adds defaults to all routes'); $this->assertEquals(['admin' => 'admin'], $collection->get('bar')->getDefaults(), '->addPrefix() adds defaults to all routes'); $this->assertEquals(['admin' => '\d+'], $collection->get('foo')->getRequirements(), '->addPrefix() adds requirements to all routes'); $this->assertEquals(['admin' => '\d+'], $collection->get('bar')->getRequirements(), '->addPrefix() adds requirements to all routes'); $collection->addPrefix('0'); $this->assertEquals('/0/{admin}/foo', $collection->get('foo')->getPath(), '->addPrefix() ensures a prefix must start with a slash and must not end with a slash'); $collection->addPrefix('/ /'); $this->assertSame('/ /0/{admin}/foo', $collection->get('foo')->getPath(), '->addPrefix() can handle spaces if desired'); $this->assertSame('/ /0/{admin}/bar', $collection->get('bar')->getPath(), 'the route pattern of an added collection is in synch with the added prefix'); } public function testAddPrefixOverridesDefaultsAndRequirements() { $collection = new RouteCollection(); $collection->add('foo', $foo = new Route('/foo.{_format}')); $collection->add('bar', $bar = new Route('/bar.{_format}', [], ['_format' => 'json'])); $collection->addPrefix('/admin', [], ['_format' => 'html']); $this->assertEquals('html', $collection->get('foo')->getRequirement('_format'), '->addPrefix() overrides existing requirements'); $this->assertEquals('html', $collection->get('bar')->getRequirement('_format'), '->addPrefix() overrides existing requirements'); } public function testResource() { $collection = new RouteCollection(); $collection->addResource($foo = new FileResource(__DIR__.'/Fixtures/foo.xml')); $collection->addResource($bar = new FileResource(__DIR__.'/Fixtures/bar.xml')); $collection->addResource(new FileResource(__DIR__.'/Fixtures/foo.xml')); $this->assertEquals([$foo, $bar], $collection->getResources(), '->addResource() adds a resource and getResources() only returns unique ones by comparing the string representation'); } public function testUniqueRouteWithGivenName() { $collection1 = new RouteCollection(); $collection1->add('foo', new Route('/old')); $collection2 = new RouteCollection(); $collection3 = new RouteCollection(); $collection3->add('foo', $new = new Route('/new')); $collection2->addCollection($collection3); $collection1->addCollection($collection2); $this->assertSame($new, $collection1->get('foo'), '->get() returns new route that overrode previous one'); // size of 1 because collection1 contains /new but not /old anymore $this->assertCount(1, $collection1->getIterator(), '->addCollection() removes previous routes when adding new routes with the same name'); } public function testGet() { $collection1 = new RouteCollection(); $collection1->add('a', $a = new Route('/a')); $collection2 = new RouteCollection(); $collection2->add('b', $b = new Route('/b')); $collection1->addCollection($collection2); $collection1->add('$péß^a|', $c = new Route('/special')); $this->assertSame($b, $collection1->get('b'), '->get() returns correct route in child collection'); $this->assertSame($c, $collection1->get('$péß^a|'), '->get() can handle special characters'); $this->assertNull($collection2->get('a'), '->get() does not return the route defined in parent collection'); $this->assertNull($collection1->get('non-existent'), '->get() returns null when route does not exist'); $this->assertNull($collection1->get(0), '->get() does not disclose internal child RouteCollection'); } public function testRemove() { $collection = new RouteCollection(); $collection->add('foo', $foo = new Route('/foo')); $collection1 = new RouteCollection(); $collection1->add('bar', $bar = new Route('/bar')); $collection->addCollection($collection1); $collection->add('last', $last = new Route('/last')); $collection->remove('foo'); $this->assertSame(['bar' => $bar, 'last' => $last], $collection->all(), '->remove() can remove a single route'); $collection->remove(['bar', 'last']); $this->assertSame([], $collection->all(), '->remove() accepts an array and can remove multiple routes at once'); } public function testSetHost() { $collection = new RouteCollection(); $routea = new Route('/a'); $routeb = new Route('/b', [], [], [], '{locale}.example.net'); $collection->add('a', $routea); $collection->add('b', $routeb); $collection->setHost('{locale}.example.com'); $this->assertEquals('{locale}.example.com', $routea->getHost()); $this->assertEquals('{locale}.example.com', $routeb->getHost()); } public function testSetCondition() { $collection = new RouteCollection(); $routea = new Route('/a'); $routeb = new Route('/b', [], [], [], '{locale}.example.net', [], [], 'context.getMethod() == "GET"'); $collection->add('a', $routea); $collection->add('b', $routeb); $collection->setCondition('context.getMethod() == "POST"'); $this->assertEquals('context.getMethod() == "POST"', $routea->getCondition()); $this->assertEquals('context.getMethod() == "POST"', $routeb->getCondition()); } public function testClone() { $collection = new RouteCollection(); $collection->add('a', new Route('/a')); $collection->add('b', new Route('/b', ['placeholder' => 'default'], ['placeholder' => '.+'])); $clonedCollection = clone $collection; $this->assertCount(2, $clonedCollection); $this->assertEquals($collection->get('a'), $clonedCollection->get('a')); $this->assertNotSame($collection->get('a'), $clonedCollection->get('a')); $this->assertEquals($collection->get('b'), $clonedCollection->get('b')); $this->assertNotSame($collection->get('b'), $clonedCollection->get('b')); } public function testSetSchemes() { $collection = new RouteCollection(); $routea = new Route('/a', [], [], [], '', 'http'); $routeb = new Route('/b'); $collection->add('a', $routea); $collection->add('b', $routeb); $collection->setSchemes(['http', 'https']); $this->assertEquals(['http', 'https'], $routea->getSchemes()); $this->assertEquals(['http', 'https'], $routeb->getSchemes()); } public function testSetMethods() { $collection = new RouteCollection(); $routea = new Route('/a', [], [], [], '', [], ['GET', 'POST']); $routeb = new Route('/b'); $collection->add('a', $routea); $collection->add('b', $routeb); $collection->setMethods('PUT'); $this->assertEquals(['PUT'], $routea->getMethods()); $this->assertEquals(['PUT'], $routeb->getMethods()); } } Matcher/DumpedRedirectableUrlMatcherTest.php000064400000002572150312232120015210 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Matcher; use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper; use Symfony\Component\Routing\Matcher\RedirectableUrlMatcherInterface; use Symfony\Component\Routing\Matcher\UrlMatcher; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\RouteCollection; class DumpedRedirectableUrlMatcherTest extends RedirectableUrlMatcherTest { protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null) { static $i = 0; $class = 'DumpedRedirectableUrlMatcher'.++$i; $dumper = new PhpMatcherDumper($routes); eval('?>'.$dumper->dump(['class' => $class, 'base_class' => 'Symfony\Component\Routing\Tests\Matcher\TestDumpedRedirectableUrlMatcher'])); return $this->getMockBuilder($class) ->setConstructorArgs([$context ?: new RequestContext()]) ->setMethods(['redirect']) ->getMock(); } } class TestDumpedRedirectableUrlMatcher extends UrlMatcher implements RedirectableUrlMatcherInterface { public function redirect($path, $route, $scheme = null) { return []; } } Matcher/RedirectableUrlMatcherTest.php000064400000012345150312232120014050 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Matcher; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; class RedirectableUrlMatcherTest extends UrlMatcherTest { public function testMissingTrailingSlash() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo/')); $matcher = $this->getUrlMatcher($coll); $matcher->expects($this->once())->method('redirect')->willReturn([]); $matcher->match('/foo'); } public function testRedirectWhenNoSlashForNonSafeMethod() { $this->expectException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); $coll = new RouteCollection(); $coll->add('foo', new Route('/foo/')); $context = new RequestContext(); $context->setMethod('POST'); $matcher = $this->getUrlMatcher($coll, $context); $matcher->match('/foo'); } public function testSchemeRedirectRedirectsToFirstScheme() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo', [], [], [], '', ['FTP', 'HTTPS'])); $matcher = $this->getUrlMatcher($coll); $matcher ->expects($this->once()) ->method('redirect') ->with('/foo', 'foo', 'ftp') ->willReturn(['_route' => 'foo']) ; $matcher->match('/foo'); } public function testNoSchemaRedirectIfOneOfMultipleSchemesMatches() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo', [], [], [], '', ['https', 'http'])); $matcher = $this->getUrlMatcher($coll); $matcher ->expects($this->never()) ->method('redirect'); $matcher->match('/foo'); } public function testSchemeRedirectWithParams() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo/{bar}', [], [], [], '', ['https'])); $matcher = $this->getUrlMatcher($coll); $matcher ->expects($this->once()) ->method('redirect') ->with('/foo/baz', 'foo', 'https') ->willReturn(['redirect' => 'value']) ; $this->assertEquals(['_route' => 'foo', 'bar' => 'baz', 'redirect' => 'value'], $matcher->match('/foo/baz')); } public function testSlashRedirectWithParams() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo/{bar}/')); $matcher = $this->getUrlMatcher($coll); $matcher ->expects($this->once()) ->method('redirect') ->with('/foo/baz/', 'foo', null) ->willReturn(['redirect' => 'value']) ; $this->assertEquals(['_route' => 'foo', 'bar' => 'baz', 'redirect' => 'value'], $matcher->match('/foo/baz')); } public function testRedirectPreservesUrlEncoding() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo:bar/')); $matcher = $this->getUrlMatcher($coll); $matcher->expects($this->once())->method('redirect')->with('/foo%3Abar/')->willReturn([]); $matcher->match('/foo%3Abar'); } public function testSchemeRequirement() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo', [], [], [], '', ['https'])); $matcher = $this->getUrlMatcher($coll, new RequestContext()); $matcher->expects($this->once())->method('redirect')->with('/foo', 'foo', 'https')->willReturn([]); $this->assertSame(['_route' => 'foo'], $matcher->match('/foo')); } public function testFallbackPage() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo/')); $coll->add('bar', new Route('/{name}')); $matcher = $this->getUrlMatcher($coll); $matcher->expects($this->once())->method('redirect')->with('/foo/')->willReturn(['_route' => 'foo']); $this->assertSame(['_route' => 'foo'], $matcher->match('/foo')); } public function testSlashAndVerbPrecedenceWithRedirection() { $coll = new RouteCollection(); $coll->add('a', new Route('/api/customers/{customerId}/contactpersons', [], [], [], '', [], ['post'])); $coll->add('b', new Route('/api/customers/{customerId}/contactpersons/', [], [], [], '', [], ['get'])); $matcher = $this->getUrlMatcher($coll); $expected = [ '_route' => 'b', 'customerId' => '123', ]; $this->assertEquals($expected, $matcher->match('/api/customers/123/contactpersons/')); $matcher->expects($this->once())->method('redirect')->with('/api/customers/123/contactpersons/')->willReturn([]); $this->assertEquals($expected, $matcher->match('/api/customers/123/contactpersons')); } protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null) { return $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', [$routes, $context ?: new RequestContext()]); } } Matcher/UrlMatcherTest.php000064400000060501150312232120011537 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Matcher; use PHPUnit\Framework\TestCase; use Symfony\Component\Routing\Exception\MethodNotAllowedException; use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Matcher\UrlMatcher; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; class UrlMatcherTest extends TestCase { public function testNoMethodSoAllowed() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo')); $matcher = $this->getUrlMatcher($coll); $this->assertIsArray($matcher->match('/foo')); } public function testMethodNotAllowed() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo', [], [], [], '', [], ['post'])); $matcher = $this->getUrlMatcher($coll); try { $matcher->match('/foo'); $this->fail(); } catch (MethodNotAllowedException $e) { $this->assertEquals(['POST'], $e->getAllowedMethods()); } } public function testMethodNotAllowedOnRoot() { $coll = new RouteCollection(); $coll->add('foo', new Route('/', [], [], [], '', [], ['GET'])); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'POST')); try { $matcher->match('/'); $this->fail(); } catch (MethodNotAllowedException $e) { $this->assertEquals(['GET'], $e->getAllowedMethods()); } } public function testHeadAllowedWhenRequirementContainsGet() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo', [], [], [], '', [], ['get'])); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'head')); $this->assertIsArray($matcher->match('/foo')); } public function testMethodNotAllowedAggregatesAllowedMethods() { $coll = new RouteCollection(); $coll->add('foo1', new Route('/foo', [], [], [], '', [], ['post'])); $coll->add('foo2', new Route('/foo', [], [], [], '', [], ['put', 'delete'])); $matcher = $this->getUrlMatcher($coll); try { $matcher->match('/foo'); $this->fail(); } catch (MethodNotAllowedException $e) { $this->assertEquals(['POST', 'PUT', 'DELETE'], $e->getAllowedMethods()); } } public function testMatch() { // test the patterns are matched and parameters are returned $collection = new RouteCollection(); $collection->add('foo', new Route('/foo/{bar}')); $matcher = $this->getUrlMatcher($collection); try { $matcher->match('/no-match'); $this->fail(); } catch (ResourceNotFoundException $e) { } $this->assertEquals(['_route' => 'foo', 'bar' => 'baz'], $matcher->match('/foo/baz')); // test that defaults are merged $collection = new RouteCollection(); $collection->add('foo', new Route('/foo/{bar}', ['def' => 'test'])); $matcher = $this->getUrlMatcher($collection); $this->assertEquals(['_route' => 'foo', 'bar' => 'baz', 'def' => 'test'], $matcher->match('/foo/baz')); // test that route "method" is ignored if no method is given in the context $collection = new RouteCollection(); $collection->add('foo', new Route('/foo', [], [], [], '', [], ['get', 'head'])); $matcher = $this->getUrlMatcher($collection); $this->assertIsArray($matcher->match('/foo')); // route does not match with POST method context $matcher = $this->getUrlMatcher($collection, new RequestContext('', 'post')); try { $matcher->match('/foo'); $this->fail(); } catch (MethodNotAllowedException $e) { } // route does match with GET or HEAD method context $matcher = $this->getUrlMatcher($collection); $this->assertIsArray($matcher->match('/foo')); $matcher = $this->getUrlMatcher($collection, new RequestContext('', 'head')); $this->assertIsArray($matcher->match('/foo')); // route with an optional variable as the first segment $collection = new RouteCollection(); $collection->add('bar', new Route('/{bar}/foo', ['bar' => 'bar'], ['bar' => 'foo|bar'])); $matcher = $this->getUrlMatcher($collection); $this->assertEquals(['_route' => 'bar', 'bar' => 'bar'], $matcher->match('/bar/foo')); $this->assertEquals(['_route' => 'bar', 'bar' => 'foo'], $matcher->match('/foo/foo')); $collection = new RouteCollection(); $collection->add('bar', new Route('/{bar}', ['bar' => 'bar'], ['bar' => 'foo|bar'])); $matcher = $this->getUrlMatcher($collection); $this->assertEquals(['_route' => 'bar', 'bar' => 'foo'], $matcher->match('/foo')); $this->assertEquals(['_route' => 'bar', 'bar' => 'bar'], $matcher->match('/')); // route with only optional variables $collection = new RouteCollection(); $collection->add('bar', new Route('/{foo}/{bar}', ['foo' => 'foo', 'bar' => 'bar'], [])); $matcher = $this->getUrlMatcher($collection); $this->assertEquals(['_route' => 'bar', 'foo' => 'foo', 'bar' => 'bar'], $matcher->match('/')); $this->assertEquals(['_route' => 'bar', 'foo' => 'a', 'bar' => 'bar'], $matcher->match('/a')); $this->assertEquals(['_route' => 'bar', 'foo' => 'a', 'bar' => 'b'], $matcher->match('/a/b')); } public function testMatchWithPrefixes() { $collection = new RouteCollection(); $collection->add('foo', new Route('/{foo}')); $collection->addPrefix('/b'); $collection->addPrefix('/a'); $matcher = $this->getUrlMatcher($collection); $this->assertEquals(['_route' => 'foo', 'foo' => 'foo'], $matcher->match('/a/b/foo')); } public function testMatchWithDynamicPrefix() { $collection = new RouteCollection(); $collection->add('foo', new Route('/{foo}')); $collection->addPrefix('/b'); $collection->addPrefix('/{_locale}'); $matcher = $this->getUrlMatcher($collection); $this->assertEquals(['_locale' => 'fr', '_route' => 'foo', 'foo' => 'foo'], $matcher->match('/fr/b/foo')); } public function testMatchSpecialRouteName() { $collection = new RouteCollection(); $collection->add('$péß^a|', new Route('/bar')); $matcher = $this->getUrlMatcher($collection); $this->assertEquals(['_route' => '$péß^a|'], $matcher->match('/bar')); } public function testTrailingEncodedNewlineIsNotOverlooked() { $this->expectException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); $collection = new RouteCollection(); $collection->add('foo', new Route('/foo')); $matcher = $this->getUrlMatcher($collection); $matcher->match('/foo%0a'); } public function testMatchNonAlpha() { $collection = new RouteCollection(); $chars = '!"$%éà &\'()*+,./:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\[]^_`abcdefghijklmnopqrstuvwxyz{|}~-'; $collection->add('foo', new Route('/{foo}/bar', [], ['foo' => '['.preg_quote($chars).']+'], ['utf8' => true])); $matcher = $this->getUrlMatcher($collection); $this->assertEquals(['_route' => 'foo', 'foo' => $chars], $matcher->match('/'.rawurlencode($chars).'/bar')); $this->assertEquals(['_route' => 'foo', 'foo' => $chars], $matcher->match('/'.strtr($chars, ['%' => '%25']).'/bar')); } public function testMatchWithDotMetacharacterInRequirements() { $collection = new RouteCollection(); $collection->add('foo', new Route('/{foo}/bar', [], ['foo' => '.+'])); $matcher = $this->getUrlMatcher($collection); $this->assertEquals(['_route' => 'foo', 'foo' => "\n"], $matcher->match('/'.urlencode("\n").'/bar'), 'linefeed character is matched'); } public function testMatchOverriddenRoute() { $collection = new RouteCollection(); $collection->add('foo', new Route('/foo')); $collection1 = new RouteCollection(); $collection1->add('foo', new Route('/foo1')); $collection->addCollection($collection1); $matcher = $this->getUrlMatcher($collection); $this->assertEquals(['_route' => 'foo'], $matcher->match('/foo1')); $this->expectException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); $this->assertEquals([], $matcher->match('/foo')); } public function testMatchRegression() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo/{foo}')); $coll->add('bar', new Route('/foo/bar/{foo}')); $matcher = $this->getUrlMatcher($coll); $this->assertEquals(['foo' => 'bar', '_route' => 'bar'], $matcher->match('/foo/bar/bar')); $collection = new RouteCollection(); $collection->add('foo', new Route('/{bar}')); $matcher = $this->getUrlMatcher($collection); try { $matcher->match('/'); $this->fail(); } catch (ResourceNotFoundException $e) { } } public function testDefaultRequirementForOptionalVariables() { $coll = new RouteCollection(); $coll->add('test', new Route('/{page}.{_format}', ['page' => 'index', '_format' => 'html'])); $matcher = $this->getUrlMatcher($coll); $this->assertEquals(['page' => 'my-page', '_format' => 'xml', '_route' => 'test'], $matcher->match('/my-page.xml')); } public function testMatchingIsEager() { $coll = new RouteCollection(); $coll->add('test', new Route('/{foo}-{bar}-', [], ['foo' => '.+', 'bar' => '.+'])); $matcher = $this->getUrlMatcher($coll); $this->assertEquals(['foo' => 'text1-text2-text3', 'bar' => 'text4', '_route' => 'test'], $matcher->match('/text1-text2-text3-text4-')); } public function testAdjacentVariables() { $coll = new RouteCollection(); $coll->add('test', new Route('/{w}{x}{y}{z}.{_format}', ['z' => 'default-z', '_format' => 'html'], ['y' => 'y|Y'])); $matcher = $this->getUrlMatcher($coll); // 'w' eagerly matches as much as possible and the other variables match the remaining chars. // This also shows that the variables w-z must all exclude the separating char (the dot '.' in this case) by default requirement. // Otherwise they would also consume '.xml' and _format would never match as it's an optional variable. $this->assertEquals(['w' => 'wwwww', 'x' => 'x', 'y' => 'Y', 'z' => 'Z', '_format' => 'xml', '_route' => 'test'], $matcher->match('/wwwwwxYZ.xml')); // As 'y' has custom requirement and can only be of value 'y|Y', it will leave 'ZZZ' to variable z. // So with carefully chosen requirements adjacent variables, can be useful. $this->assertEquals(['w' => 'wwwww', 'x' => 'x', 'y' => 'y', 'z' => 'ZZZ', '_format' => 'html', '_route' => 'test'], $matcher->match('/wwwwwxyZZZ')); // z and _format are optional. $this->assertEquals(['w' => 'wwwww', 'x' => 'x', 'y' => 'y', 'z' => 'default-z', '_format' => 'html', '_route' => 'test'], $matcher->match('/wwwwwxy')); $this->expectException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); $matcher->match('/wxy.html'); } public function testOptionalVariableWithNoRealSeparator() { $coll = new RouteCollection(); $coll->add('test', new Route('/get{what}', ['what' => 'All'])); $matcher = $this->getUrlMatcher($coll); $this->assertEquals(['what' => 'All', '_route' => 'test'], $matcher->match('/get')); $this->assertEquals(['what' => 'Sites', '_route' => 'test'], $matcher->match('/getSites')); // Usually the character in front of an optional parameter can be left out, e.g. with pattern '/get/{what}' just '/get' would match. // But here the 't' in 'get' is not a separating character, so it makes no sense to match without it. $this->expectException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); $matcher->match('/ge'); } public function testRequiredVariableWithNoRealSeparator() { $coll = new RouteCollection(); $coll->add('test', new Route('/get{what}Suffix')); $matcher = $this->getUrlMatcher($coll); $this->assertEquals(['what' => 'Sites', '_route' => 'test'], $matcher->match('/getSitesSuffix')); } public function testDefaultRequirementOfVariable() { $coll = new RouteCollection(); $coll->add('test', new Route('/{page}.{_format}')); $matcher = $this->getUrlMatcher($coll); $this->assertEquals(['page' => 'index', '_format' => 'mobile.html', '_route' => 'test'], $matcher->match('/index.mobile.html')); } public function testDefaultRequirementOfVariableDisallowsSlash() { $this->expectException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); $coll = new RouteCollection(); $coll->add('test', new Route('/{page}.{_format}')); $matcher = $this->getUrlMatcher($coll); $matcher->match('/index.sl/ash'); } public function testDefaultRequirementOfVariableDisallowsNextSeparator() { $this->expectException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); $coll = new RouteCollection(); $coll->add('test', new Route('/{page}.{_format}', [], ['_format' => 'html|xml'])); $matcher = $this->getUrlMatcher($coll); $matcher->match('/do.t.html'); } public function testSchemeRequirement() { $this->getExpectedException() ?: $this->expectException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); $coll = new RouteCollection(); $coll->add('foo', new Route('/foo', [], [], [], '', ['https'])); $matcher = $this->getUrlMatcher($coll); $matcher->match('/foo'); } public function testCondition() { $this->expectException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); $coll = new RouteCollection(); $route = new Route('/foo'); $route->setCondition('context.getMethod() == "POST"'); $coll->add('foo', $route); $matcher = $this->getUrlMatcher($coll); $matcher->match('/foo'); } public function testRequestCondition() { $coll = new RouteCollection(); $route = new Route('/foo/{bar}'); $route->setCondition('request.getBaseUrl() == "/sub/front.php" and request.getPathInfo() == "/foo/bar"'); $coll->add('foo', $route); $matcher = $this->getUrlMatcher($coll, new RequestContext('/sub/front.php')); $this->assertEquals(['bar' => 'bar', '_route' => 'foo'], $matcher->match('/foo/bar')); } public function testDecodeOnce() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo/{foo}')); $matcher = $this->getUrlMatcher($coll); $this->assertEquals(['foo' => 'bar%23', '_route' => 'foo'], $matcher->match('/foo/bar%2523')); } public function testCannotRelyOnPrefix() { $coll = new RouteCollection(); $subColl = new RouteCollection(); $subColl->add('bar', new Route('/bar')); $subColl->addPrefix('/prefix'); // overwrite the pattern, so the prefix is not valid anymore for this route in the collection $subColl->get('bar')->setPath('/new'); $coll->addCollection($subColl); $matcher = $this->getUrlMatcher($coll); $this->assertEquals(['_route' => 'bar'], $matcher->match('/new')); } public function testWithHost() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo/{foo}', [], [], [], '{locale}.example.com')); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com')); $this->assertEquals(['foo' => 'bar', '_route' => 'foo', 'locale' => 'en'], $matcher->match('/foo/bar')); } public function testWithHostOnRouteCollection() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo/{foo}')); $coll->add('bar', new Route('/bar/{foo}', [], [], [], '{locale}.example.net')); $coll->setHost('{locale}.example.com'); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com')); $this->assertEquals(['foo' => 'bar', '_route' => 'foo', 'locale' => 'en'], $matcher->match('/foo/bar')); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com')); $this->assertEquals(['foo' => 'bar', '_route' => 'bar', 'locale' => 'en'], $matcher->match('/bar/bar')); } public function testWithOutHostHostDoesNotMatch() { $this->expectException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); $coll = new RouteCollection(); $coll->add('foo', new Route('/foo/{foo}', [], [], [], '{locale}.example.com')); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'GET', 'example.com')); $matcher->match('/foo/bar'); } public function testPathIsCaseSensitive() { $this->expectException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); $coll = new RouteCollection(); $coll->add('foo', new Route('/locale', [], ['locale' => 'EN|FR|DE'])); $matcher = $this->getUrlMatcher($coll); $matcher->match('/en'); } public function testHostIsCaseInsensitive() { $coll = new RouteCollection(); $coll->add('foo', new Route('/', [], ['locale' => 'EN|FR|DE'], [], '{locale}.example.com')); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com')); $this->assertEquals(['_route' => 'foo', 'locale' => 'en'], $matcher->match('/')); } public function testNoConfiguration() { $this->expectException('Symfony\Component\Routing\Exception\NoConfigurationException'); $coll = new RouteCollection(); $matcher = $this->getUrlMatcher($coll); $matcher->match('/'); } public function testNestedCollections() { $coll = new RouteCollection(); $subColl = new RouteCollection(); $subColl->add('a', new Route('/a')); $subColl->add('b', new Route('/b')); $subColl->add('c', new Route('/c')); $subColl->addPrefix('/p'); $coll->addCollection($subColl); $coll->add('baz', new Route('/{baz}')); $subColl = new RouteCollection(); $subColl->add('buz', new Route('/buz')); $subColl->addPrefix('/prefix'); $coll->addCollection($subColl); $matcher = $this->getUrlMatcher($coll); $this->assertEquals(['_route' => 'a'], $matcher->match('/p/a')); $this->assertEquals(['_route' => 'baz', 'baz' => 'p'], $matcher->match('/p')); $this->assertEquals(['_route' => 'buz'], $matcher->match('/prefix/buz')); } public function testSchemeAndMethodMismatch() { $this->expectException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); $coll = new RouteCollection(); $coll->add('foo', new Route('/', [], [], [], null, ['https'], ['POST'])); $matcher = $this->getUrlMatcher($coll); $matcher->match('/'); } public function testSiblingRoutes() { $coll = new RouteCollection(); $coll->add('a', (new Route('/a{a}'))->setMethods('POST')); $coll->add('b', (new Route('/a{a}'))->setMethods('PUT')); $coll->add('c', new Route('/a{a}')); $coll->add('d', (new Route('/b{a}'))->setCondition('false')); $coll->add('e', (new Route('/{b}{a}'))->setCondition('false')); $coll->add('f', (new Route('/{b}{a}'))->setRequirements(['b' => 'b'])); $matcher = $this->getUrlMatcher($coll); $this->assertEquals(['_route' => 'c', 'a' => 'a'], $matcher->match('/aa')); $this->assertEquals(['_route' => 'f', 'b' => 'b', 'a' => 'a'], $matcher->match('/ba')); } public function testRequirementWithCapturingGroup() { $coll = new RouteCollection(); $coll->add('a', new Route('/{a}/{b}', [], ['a' => '(a|b)'])); $matcher = $this->getUrlMatcher($coll); $this->assertEquals(['_route' => 'a', 'a' => 'a', 'b' => 'b'], $matcher->match('/a/b')); } public function testDotAllWithCatchAll() { $coll = new RouteCollection(); $coll->add('a', new Route('/{id}.html', [], ['id' => '.+'])); $coll->add('b', new Route('/{all}', [], ['all' => '.+'])); $matcher = $this->getUrlMatcher($coll); $this->assertEquals(['_route' => 'a', 'id' => 'foo/bar'], $matcher->match('/foo/bar.html')); } public function testHostPattern() { $coll = new RouteCollection(); $coll->add('a', new Route('/{app}/{action}/{unused}', [], [], [], '{host}')); $expected = [ '_route' => 'a', 'app' => 'an_app', 'action' => 'an_action', 'unused' => 'unused', 'host' => 'foo', ]; $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'GET', 'foo')); $this->assertEquals($expected, $matcher->match('/an_app/an_action/unused')); } public function testHostWithDot() { $coll = new RouteCollection(); $coll->add('a', new Route('/foo', [], [], [], 'foo.example.com')); $coll->add('b', new Route('/bar/{baz}')); $matcher = $this->getUrlMatcher($coll); $this->assertEquals('b', $matcher->match('/bar/abc.123')['_route']); } public function testSlashVariant() { $coll = new RouteCollection(); $coll->add('a', new Route('/foo/{bar}', [], ['bar' => '.*'])); $matcher = $this->getUrlMatcher($coll); $this->assertEquals('a', $matcher->match('/foo/')['_route']); } public function testSlashWithVerb() { $coll = new RouteCollection(); $coll->add('a', new Route('/{foo}', [], [], [], '', [], ['put', 'delete'])); $coll->add('b', new Route('/bar/')); $matcher = $this->getUrlMatcher($coll); $this->assertSame(['_route' => 'b'], $matcher->match('/bar/')); $coll = new RouteCollection(); $coll->add('a', new Route('/dav/{foo}', [], ['foo' => '.*'], [], '', [], ['GET', 'OPTIONS'])); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'OPTIONS')); $expected = [ '_route' => 'a', 'foo' => 'files/bar/', ]; $this->assertEquals($expected, $matcher->match('/dav/files/bar/')); } public function testSlashAndVerbPrecedence() { $coll = new RouteCollection(); $coll->add('a', new Route('/api/customers/{customerId}/contactpersons/', [], [], [], '', [], ['post'])); $coll->add('b', new Route('/api/customers/{customerId}/contactpersons', [], [], [], '', [], ['get'])); $matcher = $this->getUrlMatcher($coll); $expected = [ '_route' => 'b', 'customerId' => '123', ]; $this->assertEquals($expected, $matcher->match('/api/customers/123/contactpersons')); $coll = new RouteCollection(); $coll->add('a', new Route('/api/customers/{customerId}/contactpersons/', [], [], [], '', [], ['get'])); $coll->add('b', new Route('/api/customers/{customerId}/contactpersons', [], [], [], '', [], ['post'])); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'POST')); $expected = [ '_route' => 'b', 'customerId' => '123', ]; $this->assertEquals($expected, $matcher->match('/api/customers/123/contactpersons')); } public function testGreedyTrailingRequirement() { $coll = new RouteCollection(); $coll->add('a', new Route('/{a}', [], ['a' => '.+'])); $matcher = $this->getUrlMatcher($coll); $this->assertEquals(['_route' => 'a', 'a' => 'foo'], $matcher->match('/foo')); $this->assertEquals(['_route' => 'a', 'a' => 'foo/'], $matcher->match('/foo/')); } protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null) { return new UrlMatcher($routes, $context ?: new RequestContext()); } } Matcher/TraceableUrlMatcherTest.php000064400000010472150312232120013344 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Matcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Matcher\TraceableUrlMatcher; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; class TraceableUrlMatcherTest extends UrlMatcherTest { public function test() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo', [], [], [], '', [], ['POST'])); $coll->add('bar', new Route('/bar/{id}', [], ['id' => '\d+'])); $coll->add('bar1', new Route('/bar/{name}', [], ['id' => '\w+'], [], '', [], ['POST'])); $coll->add('bar2', new Route('/foo', [], [], [], 'baz')); $coll->add('bar3', new Route('/foo1', [], [], [], 'baz')); $coll->add('bar4', new Route('/foo2', [], [], [], 'baz', [], [], 'context.getMethod() == "GET"')); $context = new RequestContext(); $context->setHost('baz'); $matcher = new TraceableUrlMatcher($coll, $context); $traces = $matcher->getTraces('/babar'); $this->assertSame([0, 0, 0, 0, 0, 0], $this->getLevels($traces)); $traces = $matcher->getTraces('/foo'); $this->assertSame([1, 0, 0, 2], $this->getLevels($traces)); $traces = $matcher->getTraces('/bar/12'); $this->assertSame([0, 2], $this->getLevels($traces)); $traces = $matcher->getTraces('/bar/dd'); $this->assertSame([0, 1, 1, 0, 0, 0], $this->getLevels($traces)); $traces = $matcher->getTraces('/foo1'); $this->assertSame([0, 0, 0, 0, 2], $this->getLevels($traces)); $context->setMethod('POST'); $traces = $matcher->getTraces('/foo'); $this->assertSame([2], $this->getLevels($traces)); $traces = $matcher->getTraces('/bar/dd'); $this->assertSame([0, 1, 2], $this->getLevels($traces)); $traces = $matcher->getTraces('/foo2'); $this->assertSame([0, 0, 0, 0, 0, 1], $this->getLevels($traces)); } public function testMatchRouteOnMultipleHosts() { $routes = new RouteCollection(); $routes->add('first', new Route( '/mypath/', ['_controller' => 'MainBundle:Info:first'], [], [], 'some.example.com' )); $routes->add('second', new Route( '/mypath/', ['_controller' => 'MainBundle:Info:second'], [], [], 'another.example.com' )); $context = new RequestContext(); $context->setHost('baz'); $matcher = new TraceableUrlMatcher($routes, $context); $traces = $matcher->getTraces('/mypath/'); $this->assertSame( [TraceableUrlMatcher::ROUTE_ALMOST_MATCHES, TraceableUrlMatcher::ROUTE_ALMOST_MATCHES], $this->getLevels($traces) ); } public function getLevels($traces) { $levels = []; foreach ($traces as $trace) { $levels[] = $trace['level']; } return $levels; } public function testRoutesWithConditions() { $routes = new RouteCollection(); $routes->add('foo', new Route('/foo', [], [], [], 'baz', [], [], "request.headers.get('User-Agent') matches '/firefox/i'")); $context = new RequestContext(); $context->setHost('baz'); $matcher = new TraceableUrlMatcher($routes, $context); $notMatchingRequest = Request::create('/foo', 'GET'); $traces = $matcher->getTracesForRequest($notMatchingRequest); $this->assertEquals("Condition \"request.headers.get('User-Agent') matches '/firefox/i'\" does not evaluate to \"true\"", $traces[0]['log']); $matchingRequest = Request::create('/foo', 'GET', [], [], [], ['HTTP_USER_AGENT' => 'Firefox']); $traces = $matcher->getTracesForRequest($matchingRequest); $this->assertEquals('Route matches!', $traces[0]['log']); } protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null) { return new TraceableUrlMatcher($routes, $context ?: new RequestContext()); } } Matcher/DumpedUrlMatcherTest.php000064400000002643150312232120012701 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Matcher; use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\RouteCollection; class DumpedUrlMatcherTest extends UrlMatcherTest { public function testSchemeRequirement() { $this->expectException('LogicException'); $this->expectExceptionMessage('The "schemes" requirement is only supported for URL matchers that implement RedirectableUrlMatcherInterface.'); parent::testSchemeRequirement(); } public function testSchemeAndMethodMismatch() { $this->expectException('LogicException'); $this->expectExceptionMessage('The "schemes" requirement is only supported for URL matchers that implement RedirectableUrlMatcherInterface.'); parent::testSchemeRequirement(); } protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null) { static $i = 0; $class = 'DumpedUrlMatcher'.++$i; $dumper = new PhpMatcherDumper($routes); eval('?>'.$dumper->dump(['class' => $class])); return new $class($context ?: new RequestContext()); } } Matcher/Dumper/StaticPrefixCollectionTest.php000064400000011423150312232120015345 0ustar00compile()->getStaticPrefix(); $collection->addRoute($staticPrefix, $name); } $collection->optimizeGroups(); $dumped = $this->dumpCollection($collection); $this->assertEquals($expected, $dumped); } public function routeProvider() { return [ 'Simple - not nested' => [ [ ['/', 'root'], ['/prefix/segment/', 'prefix_segment'], ['/leading/segment/', 'leading_segment'], ], << [ [ ['/', 'root'], ['/prefix/segment/aa', 'prefix_segment'], ['/prefix/segment/bb', 'leading_segment'], ], << [ [ ['/', 'root'], ['/prefix/segment/', 'prefix_segment'], ['/prefix/segment/bb', 'leading_segment'], ], << /prefix/segment prefix_segment -> /prefix/segment/bb leading_segment EOF ], 'Simple one level nesting' => [ [ ['/', 'root'], ['/group/segment/', 'nested_segment'], ['/group/thing/', 'some_segment'], ['/group/other/', 'other_segment'], ], << /group/segment nested_segment -> /group/thing some_segment -> /group/other other_segment EOF ], 'Retain matching order with groups' => [ [ ['/group/aa/', 'aa'], ['/group/bb/', 'bb'], ['/group/cc/', 'cc'], ['/', 'root'], ['/group/dd/', 'dd'], ['/group/ee/', 'ee'], ['/group/ff/', 'ff'], ], << /group/aa aa -> /group/bb bb -> /group/cc cc / root /group -> /group/dd dd -> /group/ee ee -> /group/ff ff EOF ], 'Retain complex matching order with groups at base' => [ [ ['/aaa/111/', 'first_aaa'], ['/prefixed/group/aa/', 'aa'], ['/prefixed/group/bb/', 'bb'], ['/prefixed/group/cc/', 'cc'], ['/prefixed/', 'root'], ['/prefixed/group/dd/', 'dd'], ['/prefixed/group/ee/', 'ee'], ['/prefixed/group/ff/', 'ff'], ['/aaa/222/', 'second_aaa'], ['/aaa/333/', 'third_aaa'], ], << /aaa/111 first_aaa -> /aaa/222 second_aaa -> /aaa/333 third_aaa /prefixed -> /prefixed/group -> -> /prefixed/group/aa aa -> -> /prefixed/group/bb bb -> -> /prefixed/group/cc cc -> /prefixed root -> /prefixed/group -> -> /prefixed/group/dd dd -> -> /prefixed/group/ee ee -> -> /prefixed/group/ff ff EOF ], 'Group regardless of segments' => [ [ ['/aaa-111/', 'a1'], ['/aaa-222/', 'a2'], ['/aaa-333/', 'a3'], ['/group-aa/', 'g1'], ['/group-bb/', 'g2'], ['/group-cc/', 'g3'], ], << /aaa-111 a1 -> /aaa-222 a2 -> /aaa-333 a3 /group- -> /group-aa g1 -> /group-bb g2 -> /group-cc g3 EOF ], ]; } private function dumpCollection(StaticPrefixCollection $collection, $prefix = '') { $lines = []; foreach ($collection->getItems() as $item) { if ($item instanceof StaticPrefixCollection) { $lines[] = $prefix.$item->getPrefix(); $lines[] = $this->dumpCollection($item, $prefix.'-> '); } else { $lines[] = $prefix.implode(' ', $item); } } return implode("\n", $lines); } } Matcher/Dumper/PhpMatcherDumperTest.php000064400000041021150312232120014131 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Matcher\Dumper; use PHPUnit\Framework\TestCase; use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper; use Symfony\Component\Routing\Matcher\RedirectableUrlMatcherInterface; use Symfony\Component\Routing\Matcher\UrlMatcher; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; class PhpMatcherDumperTest extends TestCase { /** * @var string */ private $matcherClass; /** * @var string */ private $dumpPath; protected function setUp() { parent::setUp(); $this->matcherClass = uniqid('ProjectUrlMatcher'); $this->dumpPath = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'php_matcher.'.$this->matcherClass.'.php'; } protected function tearDown() { parent::tearDown(); @unlink($this->dumpPath); } public function testDumpWhenSchemeIsUsedWithoutAProperDumper() { $this->expectException('LogicException'); $collection = new RouteCollection(); $collection->add('secure', new Route( '/secure', [], [], [], '', ['https'] )); $dumper = new PhpMatcherDumper($collection); $dumper->dump(); } public function testRedirectPreservesUrlEncoding() { $collection = new RouteCollection(); $collection->add('foo', new Route('/foo:bar/')); $class = $this->generateDumpedMatcher($collection, true); $matcher = $this->getMockBuilder($class) ->setMethods(['redirect']) ->setConstructorArgs([new RequestContext()]) ->getMock(); $matcher->expects($this->once())->method('redirect')->with('/foo%3Abar/', 'foo')->willReturn([]); $matcher->match('/foo%3Abar'); } /** * @dataProvider getRouteCollections */ public function testDump(RouteCollection $collection, $fixture, $options = []) { $basePath = __DIR__.'/../../Fixtures/dumper/'; $dumper = new PhpMatcherDumper($collection); $this->assertStringEqualsFile($basePath.$fixture, $dumper->dump($options), '->dump() correctly dumps routes as optimized PHP code.'); } public function getRouteCollections() { /* test case 1 */ $collection = new RouteCollection(); $collection->add('overridden', new Route('/overridden')); // defaults and requirements $collection->add('foo', new Route( '/foo/{bar}', ['def' => 'test'], ['bar' => 'baz|symfony'] )); // method requirement $collection->add('bar', new Route( '/bar/{foo}', [], [], [], '', [], ['GET', 'head'] )); // GET method requirement automatically adds HEAD as valid $collection->add('barhead', new Route( '/barhead/{foo}', [], [], [], '', [], ['GET'] )); // simple $collection->add('baz', new Route( '/test/baz' )); // simple with extension $collection->add('baz2', new Route( '/test/baz.html' )); // trailing slash $collection->add('baz3', new Route( '/test/baz3/' )); // trailing slash with variable $collection->add('baz4', new Route( '/test/{foo}/' )); // trailing slash and method $collection->add('baz5', new Route( '/test/{foo}/', [], [], [], '', [], ['post'] )); // complex name $collection->add('baz.baz6', new Route( '/test/{foo}/', [], [], [], '', [], ['put'] )); // defaults without variable $collection->add('foofoo', new Route( '/foofoo', ['def' => 'test'] )); // pattern with quotes $collection->add('quoter', new Route( '/{quoter}', [], ['quoter' => '[\']+'] )); // space in pattern $collection->add('space', new Route( '/spa ce' )); // prefixes $collection1 = new RouteCollection(); $collection1->add('overridden', new Route('/overridden1')); $collection1->add('foo1', new Route('/{foo}')); $collection1->add('bar1', new Route('/{bar}')); $collection1->addPrefix('/b\'b'); $collection2 = new RouteCollection(); $collection2->addCollection($collection1); $collection2->add('overridden', new Route('/{var}', [], ['var' => '.*'])); $collection1 = new RouteCollection(); $collection1->add('foo2', new Route('/{foo1}')); $collection1->add('bar2', new Route('/{bar1}')); $collection1->addPrefix('/b\'b'); $collection2->addCollection($collection1); $collection2->addPrefix('/a'); $collection->addCollection($collection2); // overridden through addCollection() and multiple sub-collections with no own prefix $collection1 = new RouteCollection(); $collection1->add('overridden2', new Route('/old')); $collection1->add('helloWorld', new Route('/hello/{who}', ['who' => 'World!'])); $collection2 = new RouteCollection(); $collection3 = new RouteCollection(); $collection3->add('overridden2', new Route('/new')); $collection3->add('hey', new Route('/hey/')); $collection2->addCollection($collection3); $collection1->addCollection($collection2); $collection1->addPrefix('/multi'); $collection->addCollection($collection1); // "dynamic" prefix $collection1 = new RouteCollection(); $collection1->add('foo3', new Route('/{foo}')); $collection1->add('bar3', new Route('/{bar}')); $collection1->addPrefix('/b'); $collection1->addPrefix('{_locale}'); $collection->addCollection($collection1); // route between collections $collection->add('ababa', new Route('/ababa')); // collection with static prefix but only one route $collection1 = new RouteCollection(); $collection1->add('foo4', new Route('/{foo}')); $collection1->addPrefix('/aba'); $collection->addCollection($collection1); // prefix and host $collection1 = new RouteCollection(); $route1 = new Route('/route1', [], [], [], 'a.example.com'); $collection1->add('route1', $route1); $route2 = new Route('/c2/route2', [], [], [], 'a.example.com'); $collection1->add('route2', $route2); $route3 = new Route('/c2/route3', [], [], [], 'b.example.com'); $collection1->add('route3', $route3); $route4 = new Route('/route4', [], [], [], 'a.example.com'); $collection1->add('route4', $route4); $route5 = new Route('/route5', [], [], [], 'c.example.com'); $collection1->add('route5', $route5); $route6 = new Route('/route6', [], [], [], null); $collection1->add('route6', $route6); $collection->addCollection($collection1); // host and variables $collection1 = new RouteCollection(); $route11 = new Route('/route11', [], [], [], '{var1}.example.com'); $collection1->add('route11', $route11); $route12 = new Route('/route12', ['var1' => 'val'], [], [], '{var1}.example.com'); $collection1->add('route12', $route12); $route13 = new Route('/route13/{name}', [], [], [], '{var1}.example.com'); $collection1->add('route13', $route13); $route14 = new Route('/route14/{name}', ['var1' => 'val'], [], [], '{var1}.example.com'); $collection1->add('route14', $route14); $route15 = new Route('/route15/{name}', [], [], [], 'c.example.com'); $collection1->add('route15', $route15); $route16 = new Route('/route16/{name}', ['var1' => 'val'], [], [], null); $collection1->add('route16', $route16); $route17 = new Route('/route17', [], [], [], null); $collection1->add('route17', $route17); $collection->addCollection($collection1); // multiple sub-collections with a single route and a prefix each $collection1 = new RouteCollection(); $collection1->add('a', new Route('/a...')); $collection2 = new RouteCollection(); $collection2->add('b', new Route('/{var}')); $collection3 = new RouteCollection(); $collection3->add('c', new Route('/{var}')); $collection3->addPrefix('/c'); $collection2->addCollection($collection3); $collection2->addPrefix('/b'); $collection1->addCollection($collection2); $collection1->addPrefix('/a'); $collection->addCollection($collection1); /* test case 2 */ $redirectCollection = clone $collection; // force HTTPS redirection $redirectCollection->add('secure', new Route( '/secure', [], [], [], '', ['https'] )); // force HTTP redirection $redirectCollection->add('nonsecure', new Route( '/nonsecure', [], [], [], '', ['http'] )); /* test case 3 */ $rootprefixCollection = new RouteCollection(); $rootprefixCollection->add('static', new Route('/test')); $rootprefixCollection->add('dynamic', new Route('/{var}')); $rootprefixCollection->addPrefix('rootprefix'); $route = new Route('/with-condition'); $route->setCondition('context.getMethod() == "GET"'); $rootprefixCollection->add('with-condition', $route); /* test case 4 */ $headMatchCasesCollection = new RouteCollection(); $headMatchCasesCollection->add('just_head', new Route( '/just_head', [], [], [], '', [], ['HEAD'] )); $headMatchCasesCollection->add('head_and_get', new Route( '/head_and_get', [], [], [], '', [], ['HEAD', 'GET'] )); $headMatchCasesCollection->add('get_and_head', new Route( '/get_and_head', [], [], [], '', [], ['GET', 'HEAD'] )); $headMatchCasesCollection->add('post_and_head', new Route( '/post_and_head', [], [], [], '', [], ['POST', 'HEAD'] )); $headMatchCasesCollection->add('put_and_post', new Route( '/put_and_post', [], [], [], '', [], ['PUT', 'POST'] )); $headMatchCasesCollection->add('put_and_get_and_head', new Route( '/put_and_post', [], [], [], '', [], ['PUT', 'GET', 'HEAD'] )); /* test case 5 */ $groupOptimisedCollection = new RouteCollection(); $groupOptimisedCollection->add('a_first', new Route('/a/11')); $groupOptimisedCollection->add('a_second', new Route('/a/22')); $groupOptimisedCollection->add('a_third', new Route('/a/333')); $groupOptimisedCollection->add('a_wildcard', new Route('/{param}')); $groupOptimisedCollection->add('a_fourth', new Route('/a/44/')); $groupOptimisedCollection->add('a_fifth', new Route('/a/55/')); $groupOptimisedCollection->add('a_sixth', new Route('/a/66/')); $groupOptimisedCollection->add('nested_wildcard', new Route('/nested/{param}')); $groupOptimisedCollection->add('nested_a', new Route('/nested/group/a/')); $groupOptimisedCollection->add('nested_b', new Route('/nested/group/b/')); $groupOptimisedCollection->add('nested_c', new Route('/nested/group/c/')); $groupOptimisedCollection->add('slashed_a', new Route('/slashed/group/')); $groupOptimisedCollection->add('slashed_b', new Route('/slashed/group/b/')); $groupOptimisedCollection->add('slashed_c', new Route('/slashed/group/c/')); $trailingSlashCollection = new RouteCollection(); $trailingSlashCollection->add('simple_trailing_slash_no_methods', new Route('/trailing/simple/no-methods/', [], [], [], '', [], [])); $trailingSlashCollection->add('simple_trailing_slash_GET_method', new Route('/trailing/simple/get-method/', [], [], [], '', [], ['GET'])); $trailingSlashCollection->add('simple_trailing_slash_HEAD_method', new Route('/trailing/simple/head-method/', [], [], [], '', [], ['HEAD'])); $trailingSlashCollection->add('simple_trailing_slash_POST_method', new Route('/trailing/simple/post-method/', [], [], [], '', [], ['POST'])); $trailingSlashCollection->add('regex_trailing_slash_no_methods', new Route('/trailing/regex/no-methods/{param}/', [], [], [], '', [], [])); $trailingSlashCollection->add('regex_trailing_slash_GET_method', new Route('/trailing/regex/get-method/{param}/', [], [], [], '', [], ['GET'])); $trailingSlashCollection->add('regex_trailing_slash_HEAD_method', new Route('/trailing/regex/head-method/{param}/', [], [], [], '', [], ['HEAD'])); $trailingSlashCollection->add('regex_trailing_slash_POST_method', new Route('/trailing/regex/post-method/{param}/', [], [], [], '', [], ['POST'])); $trailingSlashCollection->add('simple_not_trailing_slash_no_methods', new Route('/not-trailing/simple/no-methods', [], [], [], '', [], [])); $trailingSlashCollection->add('simple_not_trailing_slash_GET_method', new Route('/not-trailing/simple/get-method', [], [], [], '', [], ['GET'])); $trailingSlashCollection->add('simple_not_trailing_slash_HEAD_method', new Route('/not-trailing/simple/head-method', [], [], [], '', [], ['HEAD'])); $trailingSlashCollection->add('simple_not_trailing_slash_POST_method', new Route('/not-trailing/simple/post-method', [], [], [], '', [], ['POST'])); $trailingSlashCollection->add('regex_not_trailing_slash_no_methods', new Route('/not-trailing/regex/no-methods/{param}', [], [], [], '', [], [])); $trailingSlashCollection->add('regex_not_trailing_slash_GET_method', new Route('/not-trailing/regex/get-method/{param}', [], [], [], '', [], ['GET'])); $trailingSlashCollection->add('regex_not_trailing_slash_HEAD_method', new Route('/not-trailing/regex/head-method/{param}', [], [], [], '', [], ['HEAD'])); $trailingSlashCollection->add('regex_not_trailing_slash_POST_method', new Route('/not-trailing/regex/post-method/{param}', [], [], [], '', [], ['POST'])); return [ [new RouteCollection(), 'url_matcher0.php', []], [$collection, 'url_matcher1.php', []], [$redirectCollection, 'url_matcher2.php', ['base_class' => 'Symfony\Component\Routing\Tests\Fixtures\RedirectableUrlMatcher']], [$rootprefixCollection, 'url_matcher3.php', []], [$headMatchCasesCollection, 'url_matcher4.php', []], [$groupOptimisedCollection, 'url_matcher5.php', ['base_class' => 'Symfony\Component\Routing\Tests\Fixtures\RedirectableUrlMatcher']], [$trailingSlashCollection, 'url_matcher6.php', []], [$trailingSlashCollection, 'url_matcher7.php', ['base_class' => 'Symfony\Component\Routing\Tests\Fixtures\RedirectableUrlMatcher']], ]; } private function generateDumpedMatcher(RouteCollection $collection, $redirectableStub = false) { $options = ['class' => $this->matcherClass]; if ($redirectableStub) { $options['base_class'] = '\Symfony\Component\Routing\Tests\Matcher\Dumper\RedirectableUrlMatcherStub'; } $dumper = new PhpMatcherDumper($collection); $code = $dumper->dump($options); file_put_contents($this->dumpPath, $code); include $this->dumpPath; return $this->matcherClass; } } abstract class RedirectableUrlMatcherStub extends UrlMatcher implements RedirectableUrlMatcherInterface { public function redirect($path, $route, $scheme = null) { } } Matcher/Dumper/DumperCollectionTest.php000064400000001354150312232120014176 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Matcher\Dumper; use PHPUnit\Framework\TestCase; use Symfony\Component\Routing\Matcher\Dumper\DumperCollection; class DumperCollectionTest extends TestCase { public function testGetRoot() { $a = new DumperCollection(); $b = new DumperCollection(); $a->add($b); $c = new DumperCollection(); $b->add($c); $d = new DumperCollection(); $c->add($d); $this->assertSame($a, $c->getRoot()); } } RouteCollectionBuilderTest.php000064400000035404150312232120012533 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests; use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Routing\Loader\YamlFileLoader; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\RouteCollectionBuilder; class RouteCollectionBuilderTest extends TestCase { public function testImport() { $resolvedLoader = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderInterface')->getMock(); $resolver = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderResolverInterface')->getMock(); $resolver->expects($this->once()) ->method('resolve') ->with('admin_routing.yml', 'yaml') ->willReturn($resolvedLoader); $originalRoute = new Route('/foo/path'); $expectedCollection = new RouteCollection(); $expectedCollection->add('one_test_route', $originalRoute); $expectedCollection->addResource(new FileResource(__DIR__.'/Fixtures/file_resource.yml')); $resolvedLoader ->expects($this->once()) ->method('load') ->with('admin_routing.yml', 'yaml') ->willReturn($expectedCollection); $loader = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderInterface')->getMock(); $loader->expects($this->any()) ->method('getResolver') ->willReturn($resolver); // import the file! $routes = new RouteCollectionBuilder($loader); $importedRoutes = $routes->import('admin_routing.yml', '/', 'yaml'); // we should get back a RouteCollectionBuilder $this->assertInstanceOf('Symfony\Component\Routing\RouteCollectionBuilder', $importedRoutes); // get the collection back so we can look at it $addedCollection = $importedRoutes->build(); $route = $addedCollection->get('one_test_route'); $this->assertSame($originalRoute, $route); // should return file_resource.yml, which is in the original collection $this->assertCount(1, $addedCollection->getResources()); // make sure the routes were imported into the top-level builder $routeCollection = $routes->build(); $this->assertCount(1, $routes->build()); $this->assertCount(1, $routeCollection->getResources()); } public function testImportAddResources() { $routeCollectionBuilder = new RouteCollectionBuilder(new YamlFileLoader(new FileLocator([__DIR__.'/Fixtures/']))); $routeCollectionBuilder->import('file_resource.yml'); $routeCollection = $routeCollectionBuilder->build(); $this->assertCount(1, $routeCollection->getResources()); } public function testImportWithoutLoaderThrowsException() { $this->expectException('BadMethodCallException'); $collectionBuilder = new RouteCollectionBuilder(); $collectionBuilder->import('routing.yml'); } public function testAdd() { $collectionBuilder = new RouteCollectionBuilder(); $addedRoute = $collectionBuilder->add('/checkout', 'AppBundle:Order:checkout'); $addedRoute2 = $collectionBuilder->add('/blogs', 'AppBundle:Blog:list', 'blog_list'); $this->assertInstanceOf('Symfony\Component\Routing\Route', $addedRoute); $this->assertEquals('AppBundle:Order:checkout', $addedRoute->getDefault('_controller')); $finalCollection = $collectionBuilder->build(); $this->assertSame($addedRoute2, $finalCollection->get('blog_list')); } public function testFlushOrdering() { $importedCollection = new RouteCollection(); $importedCollection->add('imported_route1', new Route('/imported/foo1')); $importedCollection->add('imported_route2', new Route('/imported/foo2')); $loader = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderInterface')->getMock(); // make this loader able to do the import - keeps mocking simple $loader->expects($this->any()) ->method('supports') ->willReturn(true); $loader ->expects($this->once()) ->method('load') ->willReturn($importedCollection); $routes = new RouteCollectionBuilder($loader); // 1) Add a route $routes->add('/checkout', 'AppBundle:Order:checkout', 'checkout_route'); // 2) Import from a file $routes->mount('/', $routes->import('admin_routing.yml')); // 3) Add another route $routes->add('/', 'AppBundle:Default:homepage', 'homepage'); // 4) Add another route $routes->add('/admin', 'AppBundle:Admin:dashboard', 'admin_dashboard'); // set a default value $routes->setDefault('_locale', 'fr'); $actualCollection = $routes->build(); $this->assertCount(5, $actualCollection); $actualRouteNames = array_keys($actualCollection->all()); $this->assertEquals([ 'checkout_route', 'imported_route1', 'imported_route2', 'homepage', 'admin_dashboard', ], $actualRouteNames); // make sure the defaults were set $checkoutRoute = $actualCollection->get('checkout_route'); $defaults = $checkoutRoute->getDefaults(); $this->assertArrayHasKey('_locale', $defaults); $this->assertEquals('fr', $defaults['_locale']); } public function testFlushSetsRouteNames() { $collectionBuilder = new RouteCollectionBuilder(); // add a "named" route $collectionBuilder->add('/admin', 'AppBundle:Admin:dashboard', 'admin_dashboard'); // add an unnamed route $collectionBuilder->add('/blogs', 'AppBundle:Blog:list') ->setMethods(['GET']); // integer route names are allowed - they don't confuse things $collectionBuilder->add('/products', 'AppBundle:Product:list', 100); $actualCollection = $collectionBuilder->build(); $actualRouteNames = array_keys($actualCollection->all()); $this->assertEquals([ 'admin_dashboard', 'GET_blogs', '100', ], $actualRouteNames); } public function testFlushSetsDetailsOnChildrenRoutes() { $routes = new RouteCollectionBuilder(); $routes->add('/blogs/{page}', 'listAction', 'blog_list') // unique things for the route ->setDefault('page', 1) ->setRequirement('id', '\d+') ->setOption('expose', true) // things that the collection will try to override (but won't) ->setDefault('_format', 'html') ->setRequirement('_format', 'json|xml') ->setOption('fooBar', true) ->setHost('example.com') ->setCondition('request.isSecure()') ->setSchemes(['https']) ->setMethods(['POST']); // a simple route, nothing added to it $routes->add('/blogs/{id}', 'editAction', 'blog_edit'); // configure the collection itself $routes // things that will not override the child route ->setDefault('_format', 'json') ->setRequirement('_format', 'xml') ->setOption('fooBar', false) ->setHost('symfony.com') ->setCondition('request.query.get("page")==1') // some unique things that should be set on the child ->setDefault('_locale', 'fr') ->setRequirement('_locale', 'fr|en') ->setOption('niceRoute', true) ->setSchemes(['http']) ->setMethods(['GET', 'POST']); $collection = $routes->build(); $actualListRoute = $collection->get('blog_list'); $this->assertEquals(1, $actualListRoute->getDefault('page')); $this->assertEquals('\d+', $actualListRoute->getRequirement('id')); $this->assertTrue($actualListRoute->getOption('expose')); // none of these should be overridden $this->assertEquals('html', $actualListRoute->getDefault('_format')); $this->assertEquals('json|xml', $actualListRoute->getRequirement('_format')); $this->assertTrue($actualListRoute->getOption('fooBar')); $this->assertEquals('example.com', $actualListRoute->getHost()); $this->assertEquals('request.isSecure()', $actualListRoute->getCondition()); $this->assertEquals(['https'], $actualListRoute->getSchemes()); $this->assertEquals(['POST'], $actualListRoute->getMethods()); // inherited from the main collection $this->assertEquals('fr', $actualListRoute->getDefault('_locale')); $this->assertEquals('fr|en', $actualListRoute->getRequirement('_locale')); $this->assertTrue($actualListRoute->getOption('niceRoute')); $actualEditRoute = $collection->get('blog_edit'); // inherited from the collection $this->assertEquals('symfony.com', $actualEditRoute->getHost()); $this->assertEquals('request.query.get("page")==1', $actualEditRoute->getCondition()); $this->assertEquals(['http'], $actualEditRoute->getSchemes()); $this->assertEquals(['GET', 'POST'], $actualEditRoute->getMethods()); } /** * @dataProvider providePrefixTests */ public function testFlushPrefixesPaths($collectionPrefix, $routePath, $expectedPath) { $routes = new RouteCollectionBuilder(); $routes->add($routePath, 'someController', 'test_route'); $outerRoutes = new RouteCollectionBuilder(); $outerRoutes->mount($collectionPrefix, $routes); $collection = $outerRoutes->build(); $this->assertEquals($expectedPath, $collection->get('test_route')->getPath()); } public function providePrefixTests() { $tests = []; // empty prefix is of course ok $tests[] = ['', '/foo', '/foo']; // normal prefix - does not matter if it's a wildcard $tests[] = ['/{admin}', '/foo', '/{admin}/foo']; // shows that a prefix will always be given the starting slash $tests[] = ['0', '/foo', '/0/foo']; // spaces are ok, and double slashes at the end are cleaned $tests[] = ['/ /', '/foo', '/ /foo']; return $tests; } public function testFlushSetsPrefixedWithMultipleLevels() { $loader = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderInterface')->getMock(); $routes = new RouteCollectionBuilder($loader); $routes->add('homepage', 'MainController::homepageAction', 'homepage'); $adminRoutes = $routes->createBuilder(); $adminRoutes->add('/dashboard', 'AdminController::dashboardAction', 'admin_dashboard'); // embedded collection under /admin $adminBlogRoutes = $routes->createBuilder(); $adminBlogRoutes->add('/new', 'BlogController::newAction', 'admin_blog_new'); // mount into admin, but before the parent collection has been mounted $adminRoutes->mount('/blog', $adminBlogRoutes); // now mount the /admin routes, above should all still be /blog/admin $routes->mount('/admin', $adminRoutes); // add a route after mounting $adminRoutes->add('/users', 'AdminController::userAction', 'admin_users'); // add another sub-collection after the mount $otherAdminRoutes = $routes->createBuilder(); $otherAdminRoutes->add('/sales', 'StatsController::indexAction', 'admin_stats_sales'); $adminRoutes->mount('/stats', $otherAdminRoutes); // add a normal collection and see that it is also prefixed $importedCollection = new RouteCollection(); $importedCollection->add('imported_route', new Route('/foo')); // make this loader able to do the import - keeps mocking simple $loader->expects($this->any()) ->method('supports') ->willReturn(true); $loader ->expects($this->any()) ->method('load') ->willReturn($importedCollection); // import this from the /admin route builder $adminRoutes->import('admin.yml', '/imported'); $collection = $routes->build(); $this->assertEquals('/admin/dashboard', $collection->get('admin_dashboard')->getPath(), 'Routes before mounting have the prefix'); $this->assertEquals('/admin/users', $collection->get('admin_users')->getPath(), 'Routes after mounting have the prefix'); $this->assertEquals('/admin/blog/new', $collection->get('admin_blog_new')->getPath(), 'Sub-collections receive prefix even if mounted before parent prefix'); $this->assertEquals('/admin/stats/sales', $collection->get('admin_stats_sales')->getPath(), 'Sub-collections receive prefix if mounted after parent prefix'); $this->assertEquals('/admin/imported/foo', $collection->get('imported_route')->getPath(), 'Normal RouteCollections are also prefixed properly'); } public function testAutomaticRouteNamesDoNotConflict() { $routes = new RouteCollectionBuilder(); $adminRoutes = $routes->createBuilder(); // route 1 $adminRoutes->add('/dashboard', ''); $accountRoutes = $routes->createBuilder(); // route 2 $accountRoutes->add('/dashboard', '') ->setMethods(['GET']); // route 3 $accountRoutes->add('/dashboard', '') ->setMethods(['POST']); $routes->mount('/admin', $adminRoutes); $routes->mount('/account', $accountRoutes); $collection = $routes->build(); // there are 2 routes (i.e. with non-conflicting names) $this->assertCount(3, $collection->all()); } public function testAddsThePrefixOnlyOnceWhenLoadingMultipleCollections() { $firstCollection = new RouteCollection(); $firstCollection->add('a', new Route('/a')); $secondCollection = new RouteCollection(); $secondCollection->add('b', new Route('/b')); $loader = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderInterface')->getMock(); $loader->expects($this->any()) ->method('supports') ->willReturn(true); $loader ->expects($this->any()) ->method('load') ->willReturn([$firstCollection, $secondCollection]); $routeCollectionBuilder = new RouteCollectionBuilder($loader); $routeCollectionBuilder->import('/directory/recurse/*', '/other/', 'glob'); $routes = $routeCollectionBuilder->build()->all(); $this->assertCount(2, $routes); $this->assertEquals('/other/a', $routes['a']->getPath()); $this->assertEquals('/other/b', $routes['b']->getPath()); } } Generator/UrlGeneratorTest.php000064400000100422150312232120012442 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Generator; use PHPUnit\Framework\TestCase; use Symfony\Component\Routing\Generator\UrlGenerator; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; class UrlGeneratorTest extends TestCase { public function testAbsoluteUrlWithPort80() { $routes = $this->getRoutes('test', new Route('/testing')); $url = $this->getGenerator($routes)->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL); $this->assertEquals('http://localhost/app.php/testing', $url); } public function testAbsoluteSecureUrlWithPort443() { $routes = $this->getRoutes('test', new Route('/testing')); $url = $this->getGenerator($routes, ['scheme' => 'https'])->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL); $this->assertEquals('https://localhost/app.php/testing', $url); } public function testAbsoluteUrlWithNonStandardPort() { $routes = $this->getRoutes('test', new Route('/testing')); $url = $this->getGenerator($routes, ['httpPort' => 8080])->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL); $this->assertEquals('http://localhost:8080/app.php/testing', $url); } public function testAbsoluteSecureUrlWithNonStandardPort() { $routes = $this->getRoutes('test', new Route('/testing')); $url = $this->getGenerator($routes, ['httpsPort' => 8080, 'scheme' => 'https'])->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL); $this->assertEquals('https://localhost:8080/app.php/testing', $url); } public function testRelativeUrlWithoutParameters() { $routes = $this->getRoutes('test', new Route('/testing')); $url = $this->getGenerator($routes)->generate('test', [], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('/app.php/testing', $url); } public function testRelativeUrlWithParameter() { $routes = $this->getRoutes('test', new Route('/testing/{foo}')); $url = $this->getGenerator($routes)->generate('test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('/app.php/testing/bar', $url); } public function testRelativeUrlWithNullParameter() { $routes = $this->getRoutes('test', new Route('/testing.{format}', ['format' => null])); $url = $this->getGenerator($routes)->generate('test', [], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('/app.php/testing', $url); } public function testRelativeUrlWithNullParameterButNotOptional() { $this->expectException('Symfony\Component\Routing\Exception\InvalidParameterException'); $routes = $this->getRoutes('test', new Route('/testing/{foo}/bar', ['foo' => null])); // This must raise an exception because the default requirement for "foo" is "[^/]+" which is not met with these params. // Generating path "/testing//bar" would be wrong as matching this route would fail. $this->getGenerator($routes)->generate('test', [], UrlGeneratorInterface::ABSOLUTE_PATH); } public function testRelativeUrlWithOptionalZeroParameter() { $routes = $this->getRoutes('test', new Route('/testing/{page}')); $url = $this->getGenerator($routes)->generate('test', ['page' => 0], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('/app.php/testing/0', $url); } public function testNotPassedOptionalParameterInBetween() { $routes = $this->getRoutes('test', new Route('/{slug}/{page}', ['slug' => 'index', 'page' => 0])); $this->assertSame('/app.php/index/1', $this->getGenerator($routes)->generate('test', ['page' => 1])); $this->assertSame('/app.php/', $this->getGenerator($routes)->generate('test')); } public function testRelativeUrlWithExtraParameters() { $routes = $this->getRoutes('test', new Route('/testing')); $url = $this->getGenerator($routes)->generate('test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('/app.php/testing?foo=bar', $url); } public function testAbsoluteUrlWithExtraParameters() { $routes = $this->getRoutes('test', new Route('/testing')); $url = $this->getGenerator($routes)->generate('test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_URL); $this->assertEquals('http://localhost/app.php/testing?foo=bar', $url); } public function testUrlWithNullExtraParameters() { $routes = $this->getRoutes('test', new Route('/testing')); $url = $this->getGenerator($routes)->generate('test', ['foo' => null], UrlGeneratorInterface::ABSOLUTE_URL); $this->assertEquals('http://localhost/app.php/testing', $url); } public function testUrlWithExtraParametersFromGlobals() { $routes = $this->getRoutes('test', new Route('/testing')); $generator = $this->getGenerator($routes); $context = new RequestContext('/app.php'); $context->setParameter('bar', 'bar'); $generator->setContext($context); $url = $generator->generate('test', ['foo' => 'bar']); $this->assertEquals('/app.php/testing?foo=bar', $url); } public function testUrlWithGlobalParameter() { $routes = $this->getRoutes('test', new Route('/testing/{foo}')); $generator = $this->getGenerator($routes); $context = new RequestContext('/app.php'); $context->setParameter('foo', 'bar'); $generator->setContext($context); $url = $generator->generate('test', []); $this->assertEquals('/app.php/testing/bar', $url); } public function testGlobalParameterHasHigherPriorityThanDefault() { $routes = $this->getRoutes('test', new Route('/{_locale}', ['_locale' => 'en'])); $generator = $this->getGenerator($routes); $context = new RequestContext('/app.php'); $context->setParameter('_locale', 'de'); $generator->setContext($context); $url = $generator->generate('test', []); $this->assertSame('/app.php/de', $url); } public function testGenerateWithoutRoutes() { $this->expectException('Symfony\Component\Routing\Exception\RouteNotFoundException'); $routes = $this->getRoutes('foo', new Route('/testing/{foo}')); $this->getGenerator($routes)->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL); } public function testGenerateForRouteWithoutMandatoryParameter() { $this->expectException('Symfony\Component\Routing\Exception\MissingMandatoryParametersException'); $routes = $this->getRoutes('test', new Route('/testing/{foo}')); $this->getGenerator($routes)->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL); } public function testGenerateForRouteWithInvalidOptionalParameter() { $this->expectException('Symfony\Component\Routing\Exception\InvalidParameterException'); $routes = $this->getRoutes('test', new Route('/testing/{foo}', ['foo' => '1'], ['foo' => 'd+'])); $this->getGenerator($routes)->generate('test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_URL); } public function testGenerateForRouteWithInvalidParameter() { $this->expectException('Symfony\Component\Routing\Exception\InvalidParameterException'); $routes = $this->getRoutes('test', new Route('/testing/{foo}', [], ['foo' => '1|2'])); $this->getGenerator($routes)->generate('test', ['foo' => '0'], UrlGeneratorInterface::ABSOLUTE_URL); } public function testGenerateForRouteWithInvalidOptionalParameterNonStrict() { $routes = $this->getRoutes('test', new Route('/testing/{foo}', ['foo' => '1'], ['foo' => 'd+'])); $generator = $this->getGenerator($routes); $generator->setStrictRequirements(false); $this->assertNull($generator->generate('test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_URL)); } public function testGenerateForRouteWithInvalidOptionalParameterNonStrictWithLogger() { $routes = $this->getRoutes('test', new Route('/testing/{foo}', ['foo' => '1'], ['foo' => 'd+'])); $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); $logger->expects($this->once()) ->method('error'); $generator = $this->getGenerator($routes, [], $logger); $generator->setStrictRequirements(false); $this->assertNull($generator->generate('test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_URL)); } public function testGenerateForRouteWithInvalidParameterButDisabledRequirementsCheck() { $routes = $this->getRoutes('test', new Route('/testing/{foo}', ['foo' => '1'], ['foo' => 'd+'])); $generator = $this->getGenerator($routes); $generator->setStrictRequirements(null); $this->assertSame('/app.php/testing/bar', $generator->generate('test', ['foo' => 'bar'])); } public function testGenerateForRouteWithInvalidMandatoryParameter() { $this->expectException('Symfony\Component\Routing\Exception\InvalidParameterException'); $routes = $this->getRoutes('test', new Route('/testing/{foo}', [], ['foo' => 'd+'])); $this->getGenerator($routes)->generate('test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_URL); } public function testGenerateForRouteWithInvalidUtf8Parameter() { $this->expectException('Symfony\Component\Routing\Exception\InvalidParameterException'); $routes = $this->getRoutes('test', new Route('/testing/{foo}', [], ['foo' => '\pL+'], ['utf8' => true])); $this->getGenerator($routes)->generate('test', ['foo' => 'abc123'], UrlGeneratorInterface::ABSOLUTE_URL); } public function testRequiredParamAndEmptyPassed() { $this->expectException('Symfony\Component\Routing\Exception\InvalidParameterException'); $routes = $this->getRoutes('test', new Route('/{slug}', [], ['slug' => '.+'])); $this->getGenerator($routes)->generate('test', ['slug' => '']); } public function testSchemeRequirementDoesNothingIfSameCurrentScheme() { $routes = $this->getRoutes('test', new Route('/', [], [], [], '', ['http'])); $this->assertEquals('/app.php/', $this->getGenerator($routes)->generate('test')); $routes = $this->getRoutes('test', new Route('/', [], [], [], '', ['https'])); $this->assertEquals('/app.php/', $this->getGenerator($routes, ['scheme' => 'https'])->generate('test')); } public function testSchemeRequirementForcesAbsoluteUrl() { $routes = $this->getRoutes('test', new Route('/', [], [], [], '', ['https'])); $this->assertEquals('https://localhost/app.php/', $this->getGenerator($routes)->generate('test')); $routes = $this->getRoutes('test', new Route('/', [], [], [], '', ['http'])); $this->assertEquals('http://localhost/app.php/', $this->getGenerator($routes, ['scheme' => 'https'])->generate('test')); } public function testSchemeRequirementCreatesUrlForFirstRequiredScheme() { $routes = $this->getRoutes('test', new Route('/', [], [], [], '', ['Ftp', 'https'])); $this->assertEquals('ftp://localhost/app.php/', $this->getGenerator($routes)->generate('test')); } public function testPathWithTwoStartingSlashes() { $routes = $this->getRoutes('test', new Route('//path-and-not-domain')); // this must not generate '//path-and-not-domain' because that would be a network path $this->assertSame('/path-and-not-domain', $this->getGenerator($routes, ['BaseUrl' => ''])->generate('test')); } public function testNoTrailingSlashForMultipleOptionalParameters() { $routes = $this->getRoutes('test', new Route('/category/{slug1}/{slug2}/{slug3}', ['slug2' => null, 'slug3' => null])); $this->assertEquals('/app.php/category/foo', $this->getGenerator($routes)->generate('test', ['slug1' => 'foo'])); } public function testWithAnIntegerAsADefaultValue() { $routes = $this->getRoutes('test', new Route('/{default}', ['default' => 0])); $this->assertEquals('/app.php/foo', $this->getGenerator($routes)->generate('test', ['default' => 'foo'])); } public function testNullForOptionalParameterIsIgnored() { $routes = $this->getRoutes('test', new Route('/test/{default}', ['default' => 0])); $this->assertEquals('/app.php/test', $this->getGenerator($routes)->generate('test', ['default' => null])); } public function testQueryParamSameAsDefault() { $routes = $this->getRoutes('test', new Route('/test', ['page' => 1])); $this->assertSame('/app.php/test?page=2', $this->getGenerator($routes)->generate('test', ['page' => 2])); $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', ['page' => 1])); $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', ['page' => '1'])); $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test')); } public function testArrayQueryParamSameAsDefault() { $routes = $this->getRoutes('test', new Route('/test', ['array' => ['foo', 'bar']])); $this->assertSame('/app.php/test?array%5B0%5D=bar&array%5B1%5D=foo', $this->getGenerator($routes)->generate('test', ['array' => ['bar', 'foo']])); $this->assertSame('/app.php/test?array%5Ba%5D=foo&array%5Bb%5D=bar', $this->getGenerator($routes)->generate('test', ['array' => ['a' => 'foo', 'b' => 'bar']])); $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', ['array' => ['foo', 'bar']])); $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', ['array' => [1 => 'bar', 0 => 'foo']])); $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test')); } public function testGenerateWithSpecialRouteName() { $routes = $this->getRoutes('$péß^a|', new Route('/bar')); $this->assertSame('/app.php/bar', $this->getGenerator($routes)->generate('$péß^a|')); } public function testUrlEncoding() { $expectedPath = '/app.php/@:%5B%5D/%28%29*%27%22%20+,;-._~%26%24%3C%3E|%7B%7D%25%5C%5E%60!%3Ffoo=bar%23id' .'/@:%5B%5D/%28%29*%27%22%20+,;-._~%26%24%3C%3E|%7B%7D%25%5C%5E%60!%3Ffoo=bar%23id' .'?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'; // This tests the encoding of reserved characters that are used for delimiting of URI components (defined in RFC 3986) // and other special ASCII chars. These chars are tested as static text path, variable path and query param. $chars = '@:[]/()*\'" +,;-._~&$<>|{}%\\^`!?foo=bar#id'; $routes = $this->getRoutes('test', new Route("/$chars/{varpath}", [], ['varpath' => '.+'])); $this->assertSame($expectedPath, $this->getGenerator($routes)->generate('test', [ 'varpath' => $chars, 'query' => $chars, ])); } public function testEncodingOfRelativePathSegments() { $routes = $this->getRoutes('test', new Route('/dir/../dir/..')); $this->assertSame('/app.php/dir/%2E%2E/dir/%2E%2E', $this->getGenerator($routes)->generate('test')); $routes = $this->getRoutes('test', new Route('/dir/./dir/.')); $this->assertSame('/app.php/dir/%2E/dir/%2E', $this->getGenerator($routes)->generate('test')); $routes = $this->getRoutes('test', new Route('/a./.a/a../..a/...')); $this->assertSame('/app.php/a./.a/a../..a/...', $this->getGenerator($routes)->generate('test')); } public function testAdjacentVariables() { $routes = $this->getRoutes('test', new Route('/{x}{y}{z}.{_format}', ['z' => 'default-z', '_format' => 'html'], ['y' => '\d+'])); $generator = $this->getGenerator($routes); $this->assertSame('/app.php/foo123', $generator->generate('test', ['x' => 'foo', 'y' => '123'])); $this->assertSame('/app.php/foo123bar.xml', $generator->generate('test', ['x' => 'foo', 'y' => '123', 'z' => 'bar', '_format' => 'xml'])); // The default requirement for 'x' should not allow the separator '.' in this case because it would otherwise match everything // and following optional variables like _format could never match. $this->expectException('Symfony\Component\Routing\Exception\InvalidParameterException'); $generator->generate('test', ['x' => 'do.t', 'y' => '123', 'z' => 'bar', '_format' => 'xml']); } public function testOptionalVariableWithNoRealSeparator() { $routes = $this->getRoutes('test', new Route('/get{what}', ['what' => 'All'])); $generator = $this->getGenerator($routes); $this->assertSame('/app.php/get', $generator->generate('test')); $this->assertSame('/app.php/getSites', $generator->generate('test', ['what' => 'Sites'])); } public function testRequiredVariableWithNoRealSeparator() { $routes = $this->getRoutes('test', new Route('/get{what}Suffix')); $generator = $this->getGenerator($routes); $this->assertSame('/app.php/getSitesSuffix', $generator->generate('test', ['what' => 'Sites'])); } public function testDefaultRequirementOfVariable() { $routes = $this->getRoutes('test', new Route('/{page}.{_format}')); $generator = $this->getGenerator($routes); $this->assertSame('/app.php/index.mobile.html', $generator->generate('test', ['page' => 'index', '_format' => 'mobile.html'])); } public function testDefaultRequirementOfVariableDisallowsSlash() { $this->expectException('Symfony\Component\Routing\Exception\InvalidParameterException'); $routes = $this->getRoutes('test', new Route('/{page}.{_format}')); $this->getGenerator($routes)->generate('test', ['page' => 'index', '_format' => 'sl/ash']); } public function testDefaultRequirementOfVariableDisallowsNextSeparator() { $this->expectException('Symfony\Component\Routing\Exception\InvalidParameterException'); $routes = $this->getRoutes('test', new Route('/{page}.{_format}')); $this->getGenerator($routes)->generate('test', ['page' => 'do.t', '_format' => 'html']); } public function testWithHostDifferentFromContext() { $routes = $this->getRoutes('test', new Route('/{name}', [], [], [], '{locale}.example.com')); $this->assertEquals('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', ['name' => 'Fabien', 'locale' => 'fr'])); } public function testWithHostSameAsContext() { $routes = $this->getRoutes('test', new Route('/{name}', [], [], [], '{locale}.example.com')); $this->assertEquals('/app.php/Fabien', $this->getGenerator($routes, ['host' => 'fr.example.com'])->generate('test', ['name' => 'Fabien', 'locale' => 'fr'])); } public function testWithHostSameAsContextAndAbsolute() { $routes = $this->getRoutes('test', new Route('/{name}', [], [], [], '{locale}.example.com')); $this->assertEquals('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, ['host' => 'fr.example.com'])->generate('test', ['name' => 'Fabien', 'locale' => 'fr'], UrlGeneratorInterface::ABSOLUTE_URL)); } public function testUrlWithInvalidParameterInHost() { $this->expectException('Symfony\Component\Routing\Exception\InvalidParameterException'); $routes = $this->getRoutes('test', new Route('/', [], ['foo' => 'bar'], [], '{foo}.example.com')); $this->getGenerator($routes)->generate('test', ['foo' => 'baz'], UrlGeneratorInterface::ABSOLUTE_PATH); } public function testUrlWithInvalidParameterInHostWhenParamHasADefaultValue() { $this->expectException('Symfony\Component\Routing\Exception\InvalidParameterException'); $routes = $this->getRoutes('test', new Route('/', ['foo' => 'bar'], ['foo' => 'bar'], [], '{foo}.example.com')); $this->getGenerator($routes)->generate('test', ['foo' => 'baz'], UrlGeneratorInterface::ABSOLUTE_PATH); } public function testUrlWithInvalidParameterEqualsDefaultValueInHost() { $this->expectException('Symfony\Component\Routing\Exception\InvalidParameterException'); $routes = $this->getRoutes('test', new Route('/', ['foo' => 'baz'], ['foo' => 'bar'], [], '{foo}.example.com')); $this->getGenerator($routes)->generate('test', ['foo' => 'baz'], UrlGeneratorInterface::ABSOLUTE_PATH); } public function testUrlWithInvalidParameterInHostInNonStrictMode() { $routes = $this->getRoutes('test', new Route('/', [], ['foo' => 'bar'], [], '{foo}.example.com')); $generator = $this->getGenerator($routes); $generator->setStrictRequirements(false); $this->assertNull($generator->generate('test', ['foo' => 'baz'], UrlGeneratorInterface::ABSOLUTE_PATH)); } public function testHostIsCaseInsensitive() { $routes = $this->getRoutes('test', new Route('/', [], ['locale' => 'en|de|fr'], [], '{locale}.FooBar.com')); $generator = $this->getGenerator($routes); $this->assertSame('//EN.FooBar.com/app.php/', $generator->generate('test', ['locale' => 'EN'], UrlGeneratorInterface::NETWORK_PATH)); } public function testDefaultHostIsUsedWhenContextHostIsEmpty() { $routes = $this->getRoutes('test', new Route('/path', ['domain' => 'my.fallback.host'], ['domain' => '.+'], [], '{domain}')); $generator = $this->getGenerator($routes); $generator->getContext()->setHost(''); $this->assertSame('http://my.fallback.host/app.php/path', $generator->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL)); } public function testDefaultHostIsUsedWhenContextHostIsEmptyAndPathReferenceType() { $routes = $this->getRoutes('test', new Route('/path', ['domain' => 'my.fallback.host'], ['domain' => '.+'], [], '{domain}')); $generator = $this->getGenerator($routes); $generator->getContext()->setHost(''); $this->assertSame('//my.fallback.host/app.php/path', $generator->generate('test', [], UrlGeneratorInterface::ABSOLUTE_PATH)); } public function testAbsoluteUrlFallbackToPathIfHostIsEmptyAndSchemeIsHttp() { $routes = $this->getRoutes('test', new Route('/route')); $generator = $this->getGenerator($routes); $generator->getContext()->setHost(''); $generator->getContext()->setScheme('https'); $this->assertSame('/app.php/route', $generator->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL)); } public function testAbsoluteUrlFallbackToNetworkIfSchemeIsEmptyAndHostIsNot() { $routes = $this->getRoutes('test', new Route('/path')); $generator = $this->getGenerator($routes); $generator->getContext()->setHost('example.com'); $generator->getContext()->setScheme(''); $this->assertSame('//example.com/app.php/path', $generator->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL)); } public function testAbsoluteUrlFallbackToPathIfSchemeAndHostAreEmpty() { $routes = $this->getRoutes('test', new Route('/path')); $generator = $this->getGenerator($routes); $generator->getContext()->setHost(''); $generator->getContext()->setScheme(''); $this->assertSame('/app.php/path', $generator->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL)); } public function testAbsoluteUrlWithNonHttpSchemeAndEmptyHost() { $routes = $this->getRoutes('test', new Route('/path', [], [], [], '', ['file'])); $generator = $this->getGenerator($routes); $generator->getContext()->setBaseUrl(''); $generator->getContext()->setHost(''); $this->assertSame('file:///path', $generator->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL)); } public function testGenerateNetworkPath() { $routes = $this->getRoutes('test', new Route('/{name}', [], [], [], '{locale}.example.com', ['http'])); $this->assertSame('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', ['name' => 'Fabien', 'locale' => 'fr'], UrlGeneratorInterface::NETWORK_PATH), 'network path with different host' ); $this->assertSame('//fr.example.com/app.php/Fabien?query=string', $this->getGenerator($routes, ['host' => 'fr.example.com'])->generate('test', ['name' => 'Fabien', 'locale' => 'fr', 'query' => 'string'], UrlGeneratorInterface::NETWORK_PATH), 'network path although host same as context' ); $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, ['scheme' => 'https'])->generate('test', ['name' => 'Fabien', 'locale' => 'fr'], UrlGeneratorInterface::NETWORK_PATH), 'absolute URL because scheme requirement does not match context' ); $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', ['name' => 'Fabien', 'locale' => 'fr'], UrlGeneratorInterface::ABSOLUTE_URL), 'absolute URL with same scheme because it is requested' ); } public function testGenerateRelativePath() { $routes = new RouteCollection(); $routes->add('article', new Route('/{author}/{article}/')); $routes->add('comments', new Route('/{author}/{article}/comments')); $routes->add('host', new Route('/{article}', [], [], [], '{author}.example.com')); $routes->add('scheme', new Route('/{author}/blog', [], [], [], '', ['https'])); $routes->add('unrelated', new Route('/about')); $generator = $this->getGenerator($routes, ['host' => 'example.com', 'pathInfo' => '/fabien/symfony-is-great/']); $this->assertSame('comments', $generator->generate('comments', ['author' => 'fabien', 'article' => 'symfony-is-great'], UrlGeneratorInterface::RELATIVE_PATH) ); $this->assertSame('comments?page=2', $generator->generate('comments', ['author' => 'fabien', 'article' => 'symfony-is-great', 'page' => 2], UrlGeneratorInterface::RELATIVE_PATH) ); $this->assertSame('../twig-is-great/', $generator->generate('article', ['author' => 'fabien', 'article' => 'twig-is-great'], UrlGeneratorInterface::RELATIVE_PATH) ); $this->assertSame('../../bernhard/forms-are-great/', $generator->generate('article', ['author' => 'bernhard', 'article' => 'forms-are-great'], UrlGeneratorInterface::RELATIVE_PATH) ); $this->assertSame('//bernhard.example.com/app.php/forms-are-great', $generator->generate('host', ['author' => 'bernhard', 'article' => 'forms-are-great'], UrlGeneratorInterface::RELATIVE_PATH) ); $this->assertSame('https://example.com/app.php/bernhard/blog', $generator->generate('scheme', ['author' => 'bernhard'], UrlGeneratorInterface::RELATIVE_PATH) ); $this->assertSame('../../about', $generator->generate('unrelated', [], UrlGeneratorInterface::RELATIVE_PATH) ); } /** * @dataProvider provideRelativePaths */ public function testGetRelativePath($sourcePath, $targetPath, $expectedPath) { $this->assertSame($expectedPath, UrlGenerator::getRelativePath($sourcePath, $targetPath)); } public function provideRelativePaths() { return [ [ '/same/dir/', '/same/dir/', '', ], [ '/same/file', '/same/file', '', ], [ '/', '/file', 'file', ], [ '/', '/dir/file', 'dir/file', ], [ '/dir/file.html', '/dir/different-file.html', 'different-file.html', ], [ '/same/dir/extra-file', '/same/dir/', './', ], [ '/parent/dir/', '/parent/', '../', ], [ '/parent/dir/extra-file', '/parent/', '../', ], [ '/a/b/', '/x/y/z/', '../../x/y/z/', ], [ '/a/b/c/d/e', '/a/c/d', '../../../c/d', ], [ '/a/b/c//', '/a/b/c/', '../', ], [ '/a/b/c/', '/a/b/c//', './/', ], [ '/root/a/b/c/', '/root/x/b/c/', '../../../x/b/c/', ], [ '/a/b/c/d/', '/a', '../../../../a', ], [ '/special-chars/sp%20ce/1€/mäh/e=mc²', '/special-chars/sp%20ce/1€/<µ>/e=mc²', '../<µ>/e=mc²', ], [ 'not-rooted', 'dir/file', 'dir/file', ], [ '//dir/', '', '../../', ], [ '/dir/', '/dir/file:with-colon', './file:with-colon', ], [ '/dir/', '/dir/subdir/file:with-colon', 'subdir/file:with-colon', ], [ '/dir/', '/dir/:subdir/', './:subdir/', ], ]; } public function testFragmentsCanBeAppendedToUrls() { $routes = $this->getRoutes('test', new Route('/testing')); $url = $this->getGenerator($routes)->generate('test', ['_fragment' => 'frag ment'], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('/app.php/testing#frag%20ment', $url); $url = $this->getGenerator($routes)->generate('test', ['_fragment' => '0'], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('/app.php/testing#0', $url); } public function testFragmentsDoNotEscapeValidCharacters() { $routes = $this->getRoutes('test', new Route('/testing')); $url = $this->getGenerator($routes)->generate('test', ['_fragment' => '?/'], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('/app.php/testing#?/', $url); } public function testFragmentsCanBeDefinedAsDefaults() { $routes = $this->getRoutes('test', new Route('/testing', ['_fragment' => 'fragment'])); $url = $this->getGenerator($routes)->generate('test', [], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('/app.php/testing#fragment', $url); } /** * @dataProvider provideLookAroundRequirementsInPath */ public function testLookRoundRequirementsInPath($expected, $path, $requirement) { $routes = $this->getRoutes('test', new Route($path, [], ['foo' => $requirement, 'baz' => '.+?'])); $this->assertSame($expected, $this->getGenerator($routes)->generate('test', ['foo' => 'a/b', 'baz' => 'c/d/e'])); } public function provideLookAroundRequirementsInPath() { yield ['/app.php/a/b/b%28ar/c/d/e', '/{foo}/b(ar/{baz}', '.+(?=/b\\(ar/)']; yield ['/app.php/a/b/bar/c/d/e', '/{foo}/bar/{baz}', '.+(?!$)']; yield ['/app.php/bar/a/b/bam/c/d/e', '/bar/{foo}/bam/{baz}', '(?<=/bar/).+']; yield ['/app.php/bar/a/b/bam/c/d/e', '/bar/{foo}/bam/{baz}', '(? $value) { $method = 'set'.$key; $context->$method($value); } return new UrlGenerator($routes, $context, $logger); } protected function getRoutes($name, Route $route) { $routes = new RouteCollection(); $routes->add($name, $route); return $routes; } } Generator/Dumper/PhpGeneratorDumperTest.php000064400000016347150312232120015054 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Tests\Generator\Dumper; use PHPUnit\Framework\TestCase; use Symfony\Component\Routing\Generator\Dumper\PhpGeneratorDumper; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; class PhpGeneratorDumperTest extends TestCase { /** * @var RouteCollection */ private $routeCollection; /** * @var PhpGeneratorDumper */ private $generatorDumper; /** * @var string */ private $testTmpFilepath; /** * @var string */ private $largeTestTmpFilepath; protected function setUp() { parent::setUp(); $this->routeCollection = new RouteCollection(); $this->generatorDumper = new PhpGeneratorDumper($this->routeCollection); $this->testTmpFilepath = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'php_generator.'.$this->getName().'.php'; $this->largeTestTmpFilepath = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'php_generator.'.$this->getName().'.large.php'; @unlink($this->testTmpFilepath); @unlink($this->largeTestTmpFilepath); } protected function tearDown() { parent::tearDown(); @unlink($this->testTmpFilepath); $this->routeCollection = null; $this->generatorDumper = null; $this->testTmpFilepath = null; } public function testDumpWithRoutes() { $this->routeCollection->add('Test', new Route('/testing/{foo}')); $this->routeCollection->add('Test2', new Route('/testing2')); file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump()); include $this->testTmpFilepath; $projectUrlGenerator = new \ProjectUrlGenerator(new RequestContext('/app.php')); $absoluteUrlWithParameter = $projectUrlGenerator->generate('Test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_URL); $absoluteUrlWithoutParameter = $projectUrlGenerator->generate('Test2', [], UrlGeneratorInterface::ABSOLUTE_URL); $relativeUrlWithParameter = $projectUrlGenerator->generate('Test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_PATH); $relativeUrlWithoutParameter = $projectUrlGenerator->generate('Test2', [], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('http://localhost/app.php/testing/bar', $absoluteUrlWithParameter); $this->assertEquals('http://localhost/app.php/testing2', $absoluteUrlWithoutParameter); $this->assertEquals('/app.php/testing/bar', $relativeUrlWithParameter); $this->assertEquals('/app.php/testing2', $relativeUrlWithoutParameter); } public function testDumpWithTooManyRoutes() { if (\defined('HHVM_VERSION_ID')) { $this->markTestSkipped('HHVM consumes too much memory on this test.'); } $this->routeCollection->add('Test', new Route('/testing/{foo}')); for ($i = 0; $i < 32769; ++$i) { $this->routeCollection->add('route_'.$i, new Route('/route_'.$i)); } $this->routeCollection->add('Test2', new Route('/testing2')); file_put_contents($this->largeTestTmpFilepath, $this->generatorDumper->dump([ 'class' => 'ProjectLargeUrlGenerator', ])); $this->routeCollection = $this->generatorDumper = null; include $this->largeTestTmpFilepath; $projectUrlGenerator = new \ProjectLargeUrlGenerator(new RequestContext('/app.php')); $absoluteUrlWithParameter = $projectUrlGenerator->generate('Test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_URL); $absoluteUrlWithoutParameter = $projectUrlGenerator->generate('Test2', [], UrlGeneratorInterface::ABSOLUTE_URL); $relativeUrlWithParameter = $projectUrlGenerator->generate('Test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_PATH); $relativeUrlWithoutParameter = $projectUrlGenerator->generate('Test2', [], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('http://localhost/app.php/testing/bar', $absoluteUrlWithParameter); $this->assertEquals('http://localhost/app.php/testing2', $absoluteUrlWithoutParameter); $this->assertEquals('/app.php/testing/bar', $relativeUrlWithParameter); $this->assertEquals('/app.php/testing2', $relativeUrlWithoutParameter); } public function testDumpWithoutRoutes() { $this->expectException('InvalidArgumentException'); file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump(['class' => 'WithoutRoutesUrlGenerator'])); include $this->testTmpFilepath; $projectUrlGenerator = new \WithoutRoutesUrlGenerator(new RequestContext('/app.php')); $projectUrlGenerator->generate('Test', []); } public function testGenerateNonExistingRoute() { $this->expectException('Symfony\Component\Routing\Exception\RouteNotFoundException'); $this->routeCollection->add('Test', new Route('/test')); file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump(['class' => 'NonExistingRoutesUrlGenerator'])); include $this->testTmpFilepath; $projectUrlGenerator = new \NonExistingRoutesUrlGenerator(new RequestContext()); $projectUrlGenerator->generate('NonExisting', []); } public function testDumpForRouteWithDefaults() { $this->routeCollection->add('Test', new Route('/testing/{foo}', ['foo' => 'bar'])); file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump(['class' => 'DefaultRoutesUrlGenerator'])); include $this->testTmpFilepath; $projectUrlGenerator = new \DefaultRoutesUrlGenerator(new RequestContext()); $url = $projectUrlGenerator->generate('Test', []); $this->assertEquals('/testing', $url); } public function testDumpWithSchemeRequirement() { $this->routeCollection->add('Test1', new Route('/testing', [], [], [], '', ['ftp', 'https'])); file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump(['class' => 'SchemeUrlGenerator'])); include $this->testTmpFilepath; $projectUrlGenerator = new \SchemeUrlGenerator(new RequestContext('/app.php')); $absoluteUrl = $projectUrlGenerator->generate('Test1', [], UrlGeneratorInterface::ABSOLUTE_URL); $relativeUrl = $projectUrlGenerator->generate('Test1', [], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('ftp://localhost/app.php/testing', $absoluteUrl); $this->assertEquals('ftp://localhost/app.php/testing', $relativeUrl); $projectUrlGenerator = new \SchemeUrlGenerator(new RequestContext('/app.php', 'GET', 'localhost', 'https')); $absoluteUrl = $projectUrlGenerator->generate('Test1', [], UrlGeneratorInterface::ABSOLUTE_URL); $relativeUrl = $projectUrlGenerator->generate('Test1', [], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('https://localhost/app.php/testing', $absoluteUrl); $this->assertEquals('/app.php/testing', $relativeUrl); } }