/** * Replaces placeholders with service container parameter values in: * - the route defaults, * - the route requirements, * - the route pattern. * * @param RouteCollection $collection */ private function resolveParameters(RouteCollection $collection) { foreach ($collection as $route) { if ($route instanceof RouteCollection) { $this->resolveParameters($route); } else { foreach ($route->getDefaults() as $name => $value) { $route->setDefault($name, $this->resolveString($value)); } foreach ($route->getRequirements() as $name => $value) { $route->setRequirement($name, $this->resolveString($value)); } $collection->setPrefix('/' . ltrim($this->resolveString($collection->getPrefix()), '/')); $route->setPattern($this->resolveString($route->getPattern())); } } }
public function testAddPrefix() { $collection = new RouteCollection(); $collection->add('foo', $foo = new Route('/foo')); $collection->add('bar', $bar = new Route('/bar')); $collection->addPrefix('/{admin}', array('admin' => 'admin'), array('admin' => '\\d+'), array('foo' => 'bar')); $this->assertEquals('/{admin}/foo', $collection->get('foo')->getPattern(), '->addPrefix() adds a prefix to all routes'); $this->assertEquals('/{admin}/bar', $collection->get('bar')->getPattern(), '->addPrefix() adds a prefix to all routes'); $this->assertEquals(array('admin' => 'admin'), $collection->get('foo')->getDefaults(), '->addPrefix() adds a prefix to all routes'); $this->assertEquals(array('admin' => 'admin'), $collection->get('bar')->getDefaults(), '->addPrefix() adds a prefix to all routes'); $this->assertEquals(array('admin' => '\\d+'), $collection->get('foo')->getRequirements(), '->addPrefix() adds a prefix to all routes'); $this->assertEquals(array('admin' => '\\d+'), $collection->get('bar')->getRequirements(), '->addPrefix() adds a prefix to all routes'); $this->assertEquals(array('foo' => 'bar', 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler'), $collection->get('foo')->getOptions(), '->addPrefix() adds an option to all routes'); $this->assertEquals(array('foo' => 'bar', 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler'), $collection->get('bar')->getOptions(), '->addPrefix() adds an option to all routes'); $collection->addPrefix('0'); $this->assertEquals('/0/{admin}', $collection->getPrefix(), '->addPrefix() ensures a prefix must start with a slash and must not end with a slash'); }
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); $this->assertSame('', $collection->getPrefix(), '->getPrefix() is initialized with ""'); $collection->addPrefix(' / '); $this->assertSame('', $collection->getPrefix(), '->addPrefix() trims the prefix and a single slash has no effect'); $collection->addPrefix('/{admin}', array('admin' => 'admin'), array('admin' => '\d+'), array('foo' => 'bar')); $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(array('admin' => 'admin'), $collection->get('foo')->getDefaults(), '->addPrefix() adds defaults to all routes'); $this->assertEquals(array('admin' => 'admin'), $collection->get('bar')->getDefaults(), '->addPrefix() adds defaults to all routes'); $this->assertEquals(array('admin' => '\d+'), $collection->get('foo')->getRequirements(), '->addPrefix() adds requirements to all routes'); $this->assertEquals(array('admin' => '\d+'), $collection->get('bar')->getRequirements(), '->addPrefix() adds requirements to all routes'); $this->assertEquals( array('foo' => 'bar', 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler'), $collection->get('foo')->getOptions(), '->addPrefix() adds an option to all routes' ); $this->assertEquals( array('foo' => 'bar', 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler'), $collection->get('bar')->getOptions(), '->addPrefix() adds an option to all routes' ); $collection->addPrefix('0'); $this->assertEquals('/0/{admin}', $collection->getPrefix(), '->addPrefix() ensures a prefix must start with a slash and must not end with a slash'); $collection->addPrefix('/ /'); $this->assertSame('/ /0/{admin}', $collection->getPrefix(), '->addPrefix() can handle spaces if desired'); $this->assertSame('/ /0/{admin}/foo', $collection->get('foo')->getPath(), 'the route path is in synch with the collection prefix'); $this->assertSame('/ /0/{admin}/bar', $collection->get('bar')->getPath(), 'the route path in a sub-collection is in synch with the collection prefix'); }
/** * Generates PHP code recursively to match a RouteCollection with all child routes and child collections. * * @param RouteCollection $routes A RouteCollection instance * @param Boolean $supportsRedirections Whether redirections are supported by the base class * @param string|null $parentPrefix The prefix of the parent collection used to optimize the code * * @return string PHP code */ private function compileRoutes(RouteCollection $routes, $supportsRedirections, $parentPrefix = null) { $code = ''; $prefix = $routes->getPrefix(); $countDirectChildRoutes = $this->countDirectChildRoutes($routes); $countAllChildRoutes = count($routes->all()); // Can the matching be optimized by wrapping it with the prefix condition // - no need to optimize if current prefix is the same as the parent prefix // - if $countDirectChildRoutes === 0, the sub-collections can do their own optimizations (in case there are any) // - it's not worth wrapping a single child route // - prefixes with variables cannot be optimized because routes within the collection might have different requirements for the same variable $optimizable = '' !== $prefix && $prefix !== $parentPrefix && $countDirectChildRoutes > 0 && $countAllChildRoutes > 1 && false === strpos($prefix, '{'); if ($optimizable) { $code .= sprintf(" if (0 === strpos(\$pathinfo, %s)) {\n", var_export($prefix, true)); } foreach ($routes as $name => $route) { if ($route instanceof Route) { // a single route in a sub-collection is not wrapped so it should do its own optimization in ->compileRoute with $parentPrefix = null $code .= $this->compileRoute($route, $name, $supportsRedirections, 1 === $countAllChildRoutes ? null : $prefix) . "\n"; } elseif ($countAllChildRoutes - $countDirectChildRoutes > 0) { // we can stop iterating recursively if we already know there are no more routes $code .= $this->compileRoutes($route, $supportsRedirections, $prefix); } } if ($optimizable) { $code .= " }\n\n"; // apply extra indention at each line (except empty ones) $code = preg_replace('/^.{2,}$/m', ' $0', $code); } return $code; }