diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md new file mode 100644 index 0000000000..829eb016a2 --- /dev/null +++ b/UPGRADE-3.0.md @@ -0,0 +1,47 @@ +UPGRADE FROM 2.x to 3.0 +======================= + +### Routing + + * Some route settings have been renamed: + + * The `pattern` setting for a route has been deprecated in favor of `path` + * The `_scheme` and `_method` requirements have been moved to the `schemes` and `methods` settings + + Before: + + ``` + article_edit: + pattern: /article/{id} + requirements: { '_method': 'POST|PUT', '_scheme': 'https', 'id': '\d+' } + + + POST|PUT + https + \d+ + + + $route = new Route(); + $route->setPattern('/article/{id}'); + $route->setRequirement('_method', 'POST|PUT'); + $route->setRequirement('_scheme', 'https'); + ``` + + After: + + ``` + article_edit: + path: /article/{id} + methods: [POST, PUT] + schemes: https + requirements: { 'id': '\d+' } + + + \d+ + + + $route = new Route(); + $route->setPath('/article/{id}'); + $route->setMethods(array('POST', 'PUT')); + $route->setSchemes('https'); + ``` diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/RouterDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/RouterDebugCommand.php index fa3e681b89..b702ae2859 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/RouterDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/RouterDebugCommand.php @@ -92,7 +92,7 @@ EOF ? implode(', ', $requirements['_method']) : $requirements['_method'] ) : 'ANY'; - $hostname = '' !== $route->getHostnamePattern() ? $route->getHostnamePattern() : 'ANY'; + $hostname = '' !== $route->getHostname() ? $route->getHostname() : 'ANY'; $maxName = max($maxName, strlen($name)); $maxMethod = max($maxMethod, strlen($method)); $maxHostname = max($maxHostname, strlen($hostname)); @@ -109,7 +109,7 @@ EOF ? implode(', ', $requirements['_method']) : $requirements['_method'] ) : 'ANY'; - $hostname = '' !== $route->getHostnamePattern() ? $route->getHostnamePattern() : 'ANY'; + $hostname = '' !== $route->getHostname() ? $route->getHostname() : 'ANY'; $output->writeln(sprintf($format, $name, $method, $hostname, $route->getPattern())); } } @@ -124,14 +124,14 @@ EOF throw new \InvalidArgumentException(sprintf('The route "%s" does not exist.', $name)); } - $hostname = '' !== $route->getHostnamePattern() ? $route->getHostnamePattern() : 'ANY'; + $hostname = '' !== $route->getHostname() ? $route->getHostname() : 'ANY'; $output->writeln($this->getHelper('formatter')->formatSection('router', sprintf('Route "%s"', $name))); - $output->writeln(sprintf('Name %s', $name)); - $output->writeln(sprintf('Pattern %s', $route->getPattern())); - $output->writeln(sprintf('HostnamePattern %s', $hostname)); - $output->writeln(sprintf('Class %s', get_class($route))); + $output->writeln(sprintf('Name %s', $name)); + $output->writeln(sprintf('Pattern %s', $route->getPattern())); + $output->writeln(sprintf('Hostname %s', $hostname)); + $output->writeln(sprintf('Class %s', get_class($route))); $defaults = ''; $d = $route->getDefaults(); diff --git a/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php b/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php index 8620ef507a..4fc81b25ae 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php +++ b/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php @@ -78,7 +78,7 @@ class Router extends BaseRouter implements WarmableInterface * - the route defaults, * - the route requirements, * - the route pattern. - * - the route hostnamePattern. + * - the route hostname. * * @param RouteCollection $collection */ @@ -94,7 +94,7 @@ class Router extends BaseRouter implements WarmableInterface } $route->setPattern($this->resolve($route->getPattern())); - $route->setHostnamePattern($this->resolve($route->getHostnamePattern())); + $route->setHostname($this->resolve($route->getHostname())); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Routing/RouterTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Routing/RouterTest.php index 59f4d061be..01dede8925 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Routing/RouterTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Routing/RouterTest.php @@ -117,12 +117,12 @@ class RoutingTest extends \PHPUnit_Framework_TestCase ); } - public function testHostnamePatternPlaceholders() + public function testHostnamePlaceholders() { $routes = new RouteCollection(); $route = new Route('foo'); - $route->setHostnamePattern('/before/%parameter.foo%/after/%%unescaped%%'); + $route->setHostname('/before/%parameter.foo%/after/%%unescaped%%'); $routes->add('foo', $route); @@ -136,7 +136,7 @@ class RoutingTest extends \PHPUnit_Framework_TestCase $this->assertEquals( '/before/foo/after/%unescaped%', - $route->getHostnamePattern() + $route->getHostname() ); } diff --git a/src/Symfony/Component/Routing/Annotation/Route.php b/src/Symfony/Component/Routing/Annotation/Route.php index d8f4b5ae93..a43cce2e71 100644 --- a/src/Symfony/Component/Routing/Annotation/Route.php +++ b/src/Symfony/Component/Routing/Annotation/Route.php @@ -20,12 +20,14 @@ namespace Symfony\Component\Routing\Annotation; */ class Route { - private $pattern; + private $path; private $name; private $requirements; private $options; private $defaults; - private $hostnamePattern; + private $hostname; + private $methods; + private $schemes; /** * Constructor. @@ -39,9 +41,11 @@ class Route $this->requirements = array(); $this->options = array(); $this->defaults = array(); + $this->methods = array(); + $this->schemes = array(); if (isset($data['value'])) { - $data['pattern'] = $data['value']; + $data['path'] = $data['value']; unset($data['value']); } @@ -54,24 +58,40 @@ class Route } } + /** + * @deprecated Deprecated in 2.2, to be removed in 3.0. Use setPath instead. + */ public function setPattern($pattern) { - $this->pattern = $pattern; + $this->path = $pattern; } + /** + * @deprecated Deprecated in 2.2, to be removed in 3.0. Use getPath instead. + */ public function getPattern() { - return $this->pattern; + return $this->path; } - public function setHostnamePattern($pattern) + public function setPath($path) { - $this->hostnamePattern = $pattern; + $this->path = $path; } - public function getHostnamePattern() + public function getPath() { - return $this->hostnamePattern; + return $this->path; + } + + public function setHostname($pattern) + { + $this->hostname = $pattern; + } + + public function getHostname() + { + return $this->hostname; } public function setName($name) @@ -113,4 +133,24 @@ class Route { return $this->defaults; } + + public function setSchemes($schemes) + { + $this->schemes = is_array($schemes) ? $schemes : array($schemes); + } + + public function getSchemes() + { + return $this->schemes; + } + + public function setMethods($methods) + { + $this->methods = is_array($methods) ? $methods : array($methods); + } + + public function getMethods() + { + return $this->methods; + } } diff --git a/src/Symfony/Component/Routing/CHANGELOG.md b/src/Symfony/Component/Routing/CHANGELOG.md index 503838b550..873c5f7423 100644 --- a/src/Symfony/Component/Routing/CHANGELOG.md +++ b/src/Symfony/Component/Routing/CHANGELOG.md @@ -4,6 +4,49 @@ CHANGELOG 2.2.0 ----- + * [DEPRECATION] Several route settings have been renamed (the old ones will be removed in 3.0): + + * The `pattern` setting for a route has been deprecated in favor of `path` + * The `_scheme` and `_method` requirements have been moved to the `schemes` and `methods` settings + + Before: + + ``` + article_edit: + pattern: /article/{id} + requirements: { '_method': 'POST|PUT', '_scheme': 'https', 'id': '\d+' } + + + POST|PUT + https + \d+ + + + $route = new Route(); + $route->setPattern('/article/{id}'); + $route->setRequirement('_method', 'POST|PUT'); + $route->setRequirement('_scheme', 'https'); + ``` + + After: + + ``` + article_edit: + path: /article/{id} + methods: [POST, PUT] + schemes: https + requirements: { 'id': '\d+' } + + + \d+ + + + $route = new Route(); + $route->setPath('/article/{id}'); + $route->setMethods(array('POST', 'PUT')); + $route->setSchemes('https'); + ``` + * [BC BREAK] RouteCollection does not behave like a tree structure anymore but as a flat array of Routes. So when using PHP to build the RouteCollection, you must make sure to add routes to the sub-collection before adding it to the parent diff --git a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php index 9b628d6658..66ce367617 100644 --- a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php +++ b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php @@ -28,9 +28,10 @@ use Symfony\Component\Config\Loader\LoaderResolverInterface; * The @Route annotation can be set on the class (for global parameters), * and on each method. * - * The @Route annotation main value is the route pattern. The annotation also - * recognizes three parameters: requirements, options, and name. The name parameter - * is mandatory. Here is an example of how you should be able to use it: + * The @Route annotation main value is the route path. The annotation also + * recognizes several parameters: requirements, options, defaults, schemes, + * methods, hostname, and name. The name parameter is mandatory. + * Here is an example of how you should be able to use it: * * /** * * @Route("/Blog") @@ -108,11 +109,13 @@ abstract class AnnotationClassLoader implements LoaderInterface } $globals = array( - 'pattern' => '', - 'requirements' => array(), - 'options' => array(), - 'defaults' => array(), - 'hostname_pattern' => '', + 'path' => '', + 'requirements' => array(), + 'options' => array(), + 'defaults' => array(), + 'schemes' => array(), + 'methods' => array(), + 'hostname' => '', ); $class = new \ReflectionClass($class); @@ -121,8 +124,11 @@ abstract class AnnotationClassLoader implements LoaderInterface } if ($annot = $this->reader->getClassAnnotation($class, $this->routeAnnotationClass)) { - if (null !== $annot->getPattern()) { - $globals['pattern'] = $annot->getPattern(); + // for BC reasons + if (null !== $annot->getPath()) { + $globals['path'] = $annot->getPath(); + } elseif (null !== $annot->getPattern()) { + $globals['path'] = $annot->getPattern(); } if (null !== $annot->getRequirements()) { @@ -137,8 +143,16 @@ abstract class AnnotationClassLoader implements LoaderInterface $globals['defaults'] = $annot->getDefaults(); } - if (null !== $annot->getHostnamePattern()) { - $globals['hostname_pattern'] = $annot->getHostnamePattern(); + if (null !== $annot->getSchemes()) { + $globals['schemes'] = $annot->getSchemes(); + } + + if (null !== $annot->getMethods()) { + $globals['methods'] = $annot->getMethods(); + } + + if (null !== $annot->getHostname()) { + $globals['hostname'] = $annot->getHostname(); } } @@ -172,13 +186,15 @@ abstract class AnnotationClassLoader implements LoaderInterface } $requirements = array_replace($globals['requirements'], $annot->getRequirements()); $options = array_replace($globals['options'], $annot->getOptions()); + $schemes = array_replace($globals['schemes'], $annot->getSchemes()); + $methods = array_replace($globals['methods'], $annot->getMethods()); - $hostnamePattern = $annot->getHostnamePattern(); - if (null === $hostnamePattern) { - $hostnamePattern = $globals['hostname_pattern']; + $hostname = $annot->getHostname(); + if (null === $hostname) { + $hostname = $globals['hostname']; } - $route = new Route($globals['pattern'].$annot->getPattern(), $defaults, $requirements, $options, $hostnamePattern); + $route = new Route($globals['path'].$annot->getPath(), $defaults, $requirements, $options, $hostname, $schemes, $methods); $this->configureRoute($route, $class, $method, $annot); diff --git a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php index 00a6012719..983c080211 100644 --- a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php @@ -113,13 +113,25 @@ class XmlFileLoader extends FileLoader */ protected function parseRoute(RouteCollection $collection, \DOMElement $node, $path) { - if ('' === ($id = $node->getAttribute('id')) || !$node->hasAttribute('pattern')) { - throw new \InvalidArgumentException(sprintf('The element in file "%s" must have an "id" and a "pattern" attribute.', $path)); + if ('' === ($id = $node->getAttribute('id')) || (!$node->hasAttribute('pattern') && !$node->hasAttribute('path'))) { + throw new \InvalidArgumentException(sprintf('The element in file "%s" must have an "id" and a "path" attribute.', $path)); } + if ($node->hasAttribute('pattern')) { + if ($node->hasAttribute('path')) { + throw new \InvalidArgumentException(sprintf('The element in file "%s" cannot define both a "path" and a "pattern" attribute. Use only "path".', $path)); + } + + $node->setAttribute('path', $node->getAttribute('pattern')); + $node->removeAttribute('pattern'); + } + + $schemes = array_filter(explode(' ', $node->getAttribute('schemes'))); + $methods = array_filter(explode(' ', $node->getAttribute('methods'))); + list($defaults, $requirements, $options) = $this->parseConfigs($node, $path); - $route = new Route($node->getAttribute('pattern'), $defaults, $requirements, $options, $node->getAttribute('hostname-pattern')); + $route = new Route($node->getAttribute('path'), $defaults, $requirements, $options, $node->getAttribute('hostname'), $schemes, $methods); $collection->add($id, $route); } @@ -141,7 +153,9 @@ class XmlFileLoader extends FileLoader $type = $node->getAttribute('type'); $prefix = $node->getAttribute('prefix'); - $hostnamePattern = $node->hasAttribute('hostname-pattern') ? $node->getAttribute('hostname-pattern') : null; + $hostname = $node->hasAttribute('hostname') ? $node->getAttribute('hostname') : null; + $schemes = $node->hasAttribute('schemes') ? array_filter(explode(' ', $node->getAttribute('schemes'))) : null; + $methods = $node->hasAttribute('methods') ? array_filter(explode(' ', $node->getAttribute('methods'))) : null; list($defaults, $requirements, $options) = $this->parseConfigs($node, $path); @@ -150,8 +164,14 @@ class XmlFileLoader extends FileLoader $subCollection = $this->import($resource, ('' !== $type ? $type : null), false, $file); /* @var $subCollection RouteCollection */ $subCollection->addPrefix($prefix); - if (null !== $hostnamePattern) { - $subCollection->setHostnamePattern($hostnamePattern); + if (null !== $hostname) { + $subCollection->setHostname($hostname); + } + if (null !== $schemes) { + $subCollection->setSchemes($schemes); + } + if (null !== $methods) { + $subCollection->setMethods($methods); } $subCollection->addDefaults($defaults); $subCollection->addRequirements($requirements); diff --git a/src/Symfony/Component/Routing/Loader/YamlFileLoader.php b/src/Symfony/Component/Routing/Loader/YamlFileLoader.php index 4d91cd5cd3..47c483d472 100644 --- a/src/Symfony/Component/Routing/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/Routing/Loader/YamlFileLoader.php @@ -28,7 +28,7 @@ use Symfony\Component\Config\Loader\FileLoader; class YamlFileLoader extends FileLoader { private static $availableKeys = array( - 'resource', 'type', 'prefix', 'pattern', 'hostname_pattern', 'defaults', 'requirements', 'options', + 'resource', 'type', 'prefix', 'pattern', 'path', 'hostname', 'schemes', 'methods', 'defaults', 'requirements', 'options', ); /** @@ -63,6 +63,15 @@ class YamlFileLoader extends FileLoader } foreach ($config as $name => $config) { + if (isset($config['pattern'])) { + if (isset($config['path'])) { + throw new \InvalidArgumentException(sprintf('The file "%s" cannot define both a "path" and a "pattern" attribute. Use only "path".', $path)); + } + + $config['path'] = $config['pattern']; + unset($config['pattern']); + } + $this->validate($config, $name, $path); if (isset($config['resource'])) { @@ -98,9 +107,11 @@ class YamlFileLoader extends FileLoader $defaults = isset($config['defaults']) ? $config['defaults'] : array(); $requirements = isset($config['requirements']) ? $config['requirements'] : array(); $options = isset($config['options']) ? $config['options'] : array(); - $hostnamePattern = isset($config['hostname_pattern']) ? $config['hostname_pattern'] : null; + $hostname = isset($config['hostname']) ? $config['hostname'] : ''; + $schemes = isset($config['schemes']) ? $config['schemes'] : array(); + $methods = isset($config['methods']) ? $config['methods'] : array(); - $route = new Route($config['pattern'], $defaults, $requirements, $options, $hostnamePattern); + $route = new Route($config['path'], $defaults, $requirements, $options, $hostname, $schemes, $methods); $collection->add($name, $route); } @@ -120,15 +131,23 @@ class YamlFileLoader extends FileLoader $defaults = isset($config['defaults']) ? $config['defaults'] : array(); $requirements = isset($config['requirements']) ? $config['requirements'] : array(); $options = isset($config['options']) ? $config['options'] : array(); - $hostnamePattern = isset($config['hostname_pattern']) ? $config['hostname_pattern'] : null; + $hostname = isset($config['hostname']) ? $config['hostname'] : null; + $schemes = isset($config['schemes']) ? $config['schemes'] : null; + $methods = isset($config['methods']) ? $config['methods'] : null; $this->setCurrentDir(dirname($path)); $subCollection = $this->import($config['resource'], $type, false, $file); /* @var $subCollection RouteCollection */ $subCollection->addPrefix($prefix); - if (null !== $hostnamePattern) { - $subCollection->setHostnamePattern($hostnamePattern); + if (null !== $hostname) { + $subCollection->setHostname($hostname); + } + if (null !== $schemes) { + $subCollection->setSchemes($schemes); + } + if (null !== $methods) { + $subCollection->setMethods($methods); } $subCollection->addDefaults($defaults); $subCollection->addRequirements($requirements); @@ -158,9 +177,9 @@ class YamlFileLoader extends FileLoader $path, $name, implode('", "', $extraKeys), implode('", "', self::$availableKeys) )); } - if (isset($config['resource']) && isset($config['pattern'])) { + if (isset($config['resource']) && isset($config['path'])) { throw new \InvalidArgumentException(sprintf( - 'The routing file "%s" must not specify both the "resource" key and the "pattern" key for "%s". Choose between an import and a route definition.', + 'The routing file "%s" must not specify both the "resource" key and the "path" key for "%s". Choose between an import and a route definition.', $path, $name )); } @@ -170,9 +189,9 @@ class YamlFileLoader extends FileLoader $name, $path )); } - if (!isset($config['resource']) && !isset($config['pattern'])) { + if (!isset($config['resource']) && !isset($config['path'])) { throw new \InvalidArgumentException(sprintf( - 'You must define a "pattern" for the route "%s" in file "%s".', + 'You must define a "path" for the route "%s" in file "%s".', $name, $path )); } diff --git a/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd b/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd index 3143b3ac72..7fbf94081b 100644 --- a/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd +++ b/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd @@ -17,6 +17,16 @@ + + + + + + + + + + @@ -36,8 +46,11 @@ - - + + + + + @@ -46,7 +59,9 @@ - + + + diff --git a/src/Symfony/Component/Routing/Matcher/TraceableUrlMatcher.php b/src/Symfony/Component/Routing/Matcher/TraceableUrlMatcher.php index 6ef846dd69..584d37e9a7 100644 --- a/src/Symfony/Component/Routing/Matcher/TraceableUrlMatcher.php +++ b/src/Symfony/Component/Routing/Matcher/TraceableUrlMatcher.php @@ -48,16 +48,16 @@ class TraceableUrlMatcher extends UrlMatcher if (!preg_match($compiledRoute->getRegex(), $pathinfo, $matches)) { // does it match without any requirements? - $r = new Route($route->getPattern(), $route->getDefaults(), array(), $route->getOptions()); + $r = new Route($route->getPath(), $route->getDefaults(), array(), $route->getOptions()); $cr = $r->compile(); if (!preg_match($cr->getRegex(), $pathinfo)) { - $this->addTrace(sprintf('Pattern "%s" does not match', $route->getPattern()), self::ROUTE_DOES_NOT_MATCH, $name, $route); + $this->addTrace(sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route); continue; } foreach ($route->getRequirements() as $n => $regex) { - $r = new Route($route->getPattern(), $route->getDefaults(), array($n => $regex), $route->getOptions()); + $r = new Route($route->getPath(), $route->getDefaults(), array($n => $regex), $route->getOptions()); $cr = $r->compile(); if (in_array($n, $cr->getVariables()) && !preg_match($cr->getRegex(), $pathinfo)) { @@ -104,10 +104,10 @@ class TraceableUrlMatcher extends UrlMatcher private function addTrace($log, $level = self::ROUTE_DOES_NOT_MATCH, $name = null, $route = null) { $this->traces[] = array( - 'log' => $log, - 'name' => $name, - 'level' => $level, - 'pattern' => null !== $route ? $route->getPattern() : null, + 'log' => $log, + 'name' => $name, + 'level' => $level, + 'path' => null !== $route ? $route->getPath() : null, ); } } diff --git a/src/Symfony/Component/Routing/Route.php b/src/Symfony/Component/Routing/Route.php index 701cf529e4..20cf6957a6 100644 --- a/src/Symfony/Component/Routing/Route.php +++ b/src/Symfony/Component/Routing/Route.php @@ -15,6 +15,7 @@ namespace Symfony\Component\Routing; * A Route describes a route and its parameters. * * @author Fabien Potencier + * @author Tobias Schultze * * @api */ @@ -23,14 +24,24 @@ class Route implements \Serializable /** * @var string */ - private $pattern = '/'; + private $path = '/'; /** * @var string */ - private $hostnamePattern = ''; + private $hostname = ''; - /** + /** + * @var array + */ + private $schemes = array(); + + /** + * @var array + */ + private $methods = array(); + + /** * @var array */ private $defaults = array(); @@ -57,52 +68,68 @@ class Route implements \Serializable * * * compiler_class: A class name able to compile this route instance (RouteCompiler by default) * - * @param string $pattern The path pattern to match - * @param array $defaults An array of default parameter values - * @param array $requirements An array of requirements for parameters (regexes) - * @param array $options An array of options - * @param string $hostnamePattern The hostname pattern to match + * @param string $path The path pattern to match + * @param array $defaults An array of default parameter values + * @param array $requirements An array of requirements for parameters (regexes) + * @param array $options An array of options + * @param string $hostname The hostname pattern to match + * @param string|array $schemes A required URI scheme or an array of restricted schemes + * @param string|array $methods A required HTTP method or an array of restricted methods * * @api */ - public function __construct($pattern, array $defaults = array(), array $requirements = array(), array $options = array(), $hostnamePattern = '') + public function __construct($path, array $defaults = array(), array $requirements = array(), array $options = array(), $hostname = '', $schemes = array(), $methods = array()) { - $this->setPattern($pattern); + $this->setPath($path); $this->setDefaults($defaults); $this->setRequirements($requirements); $this->setOptions($options); - $this->setHostnamePattern($hostnamePattern); + $this->setHostname($hostname); + // The conditions make sure that an initial empty $schemes/$methods does not override the corresponding requirement. + // They can be removed when the BC layer is removed. + if ($schemes) { + $this->setSchemes($schemes); + } + if ($methods) { + $this->setMethods($methods); + } } public function serialize() { return serialize(array( - 'pattern' => $this->pattern, - 'hostnamePattern' => $this->hostnamePattern, - 'defaults' => $this->defaults, + 'path' => $this->path, + 'hostname' => $this->hostname, + 'defaults' => $this->defaults, 'requirements' => $this->requirements, - 'options' => $this->options, + 'options' => $this->options, + 'schemes' => $this->schemes, + 'methods' => $this->methods, )); } public function unserialize($data) { $data = unserialize($data); - $this->pattern = $data['pattern']; - $this->hostnamePattern = $data['hostnamePattern']; + $this->path = $data['path']; + $this->hostname = $data['hostname']; $this->defaults = $data['defaults']; $this->requirements = $data['requirements']; $this->options = $data['options']; + $this->schemes = $data['schemes']; + $this->methods = $data['methods']; } /** * Returns the pattern for the path. * * @return string The pattern + * + * @deprecated Deprecated in 2.2, to be removed in 3.0. Use setPath instead. */ public function getPattern() { - return $this->pattern; + return $this->path; } /** @@ -113,12 +140,38 @@ class Route implements \Serializable * @param string $pattern The pattern * * @return Route The current Route instance + * + * @deprecated Deprecated in 2.2, to be removed in 3.0. Use setPath instead. */ public function setPattern($pattern) + { + return $this->setPath($pattern); + } + + /** + * Returns the pattern for the path. + * + * @return string The path pattern + */ + public function getPath() + { + return $this->path; + } + + /** + * Sets the pattern for the path. + * + * This method implements a fluent interface. + * + * @param string $path The path pattern + * + * @return Route The current Route instance + */ + public function setPath($path) { // A pattern must start with a slash and must not have multiple slashes at the beginning because the // generated path for this route would be confused with a network path, e.g. '//domain.com/path'. - $this->pattern = '/' . ltrim(trim($pattern), '/'); + $this->path = '/' . ltrim(trim($path), '/'); $this->compiled = null; return $this; @@ -129,9 +182,9 @@ class Route implements \Serializable * * @return string The pattern */ - public function getHostnamePattern() + public function getHostname() { - return $this->hostnamePattern; + return $this->hostname; } /** @@ -141,9 +194,83 @@ class Route implements \Serializable * * @return Route The current Route instance */ - public function setHostnamePattern($pattern) + public function setHostname($pattern) { - $this->hostnamePattern = (string) $pattern; + $this->hostname = (string) $pattern; + $this->compiled = null; + + return $this; + } + + /** + * Returns the lowercased schemes this route is restricted to. + * So an empty array means that any scheme is allowed. + * + * @return array The schemes + */ + public function getSchemes() + { + return $this->schemes; + } + + /** + * Sets the schemes (e.g. 'https') this route is restricted to. + * So an empty array means that any scheme is allowed. + * + * This method implements a fluent interface. + * + * @param string|array $schemes The scheme or an array of schemes + * + * @return Route The current Route instance + */ + public function setSchemes($schemes) + { + $this->schemes = array_map('strtolower', (array) $schemes); + + // this is to keep BC and will be removed in a future version + if ($this->schemes) { + $this->requirements['_scheme'] = implode('|', $this->schemes); + } else { + unset($this->requirements['_scheme']); + } + + $this->compiled = null; + + return $this; + } + + /** + * Returns the uppercased HTTP methods this route is restricted to. + * So an empty array means that any method is allowed. + * + * @return array The schemes + */ + public function getMethods() + { + return $this->methods; + } + + /** + * Sets the HTTP methods (e.g. 'POST') this route is restricted to. + * So an empty array means that any method is allowed. + * + * This method implements a fluent interface. + * + * @param string|array $methods The method or an array of methods + * + * @return Route The current Route instance + */ + public function setMethods($methods) + { + $this->methods = array_map('strtoupper', (array) $methods); + + // this is to keep BC and will be removed in a future version + if ($this->methods) { + $this->requirements['_method'] = implode('|', $this->methods); + } else { + unset($this->requirements['_method']); + } + $this->compiled = null; return $this; @@ -453,6 +580,13 @@ class Route implements \Serializable throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" cannot be empty.', $key)); } + // this is to keep BC and will be removed in a future version + if ('_scheme' === $key) { + $this->setSchemes(explode('|', $regex)); + } elseif ('_method' === $key) { + $this->setMethods(explode('|', $regex)); + } + return $regex; } } diff --git a/src/Symfony/Component/Routing/RouteCollection.php b/src/Symfony/Component/Routing/RouteCollection.php index 4df6f7d145..f1a67e7b90 100644 --- a/src/Symfony/Component/Routing/RouteCollection.php +++ b/src/Symfony/Component/Routing/RouteCollection.php @@ -235,7 +235,7 @@ class RouteCollection implements \IteratorAggregate, \Countable $options = func_num_args() > 3 ? func_get_arg(3) : array(); foreach ($this->routes as $route) { - $route->setPattern('/' . $prefix . $route->getPattern()); + $route->setPath('/' . $prefix . $route->getPath()); $route->addDefaults($defaults); $route->addRequirements($requirements); $route->addOptions($options); @@ -261,10 +261,10 @@ class RouteCollection implements \IteratorAggregate, \Countable * @param array $defaults An array of default values * @param array $requirements An array of requirements */ - public function setHostnamePattern($pattern, array $defaults = array(), array $requirements = array()) + public function setHostname($pattern, array $defaults = array(), array $requirements = array()) { foreach ($this->routes as $route) { - $route->setHostnamePattern($pattern); + $route->setHostname($pattern); $route->addDefaults($defaults); $route->addRequirements($requirements); } @@ -318,6 +318,30 @@ class RouteCollection implements \IteratorAggregate, \Countable } } + /** + * Sets the schemes (e.g. 'https') all child routes are restricted to. + * + * @param string|array $schemes The scheme or an array of schemes + */ + public function setSchemes($schemes) + { + foreach ($this->routes as $route) { + $route->setSchemes($schemes); + } + } + + /** + * Sets the HTTP methods (e.g. 'POST') all child routes are restricted to. + * + * @param string|array $methods The method or an array of methods + */ + public function setMethods($methods) + { + foreach ($this->routes as $route) { + $route->setMethods($methods); + } + } + /** * Returns an array of resources loaded to build this collection. * diff --git a/src/Symfony/Component/Routing/RouteCompiler.php b/src/Symfony/Component/Routing/RouteCompiler.php index 70ebe77894..4d6645fc58 100644 --- a/src/Symfony/Component/Routing/RouteCompiler.php +++ b/src/Symfony/Component/Routing/RouteCompiler.php @@ -46,8 +46,8 @@ class RouteCompiler implements RouteCompilerInterface $hostnameRegex = null; $hostnameTokens = array(); - if ('' !== $hostnamePattern = $route->getHostnamePattern()) { - $result = self::compilePattern($route, $hostnamePattern, true); + if ('' !== $hostname = $route->getHostname()) { + $result = self::compilePattern($route, $hostname, true); $hostnameVariables = $result['variables']; $variables = array_merge($variables, $hostnameVariables); @@ -56,9 +56,9 @@ class RouteCompiler implements RouteCompilerInterface $hostnameRegex = $result['regex']; } - $pattern = $route->getPattern(); + $path = $route->getPath(); - $result = self::compilePattern($route, $pattern, false); + $result = self::compilePattern($route, $path, false); $staticPrefix = $result['staticPrefix']; diff --git a/src/Symfony/Component/Routing/Tests/Annotation/RouteTest.php b/src/Symfony/Component/Routing/Tests/Annotation/RouteTest.php index e1da002700..53183e9581 100644 --- a/src/Symfony/Component/Routing/Tests/Annotation/RouteTest.php +++ b/src/Symfony/Component/Routing/Tests/Annotation/RouteTest.php @@ -36,11 +36,14 @@ class RouteTest extends \PHPUnit_Framework_TestCase { return array( array('value', '/Blog', 'getPattern'), + array('value', '/Blog', 'getPath'), array('requirements', array('_method' => 'GET'), 'getRequirements'), array('options', array('compiler_class' => 'RouteCompiler'), 'getOptions'), array('name', 'blog_index', 'getName'), array('defaults', array('_controller' => 'MyBlogBundle:Blog:index'), 'getDefaults'), - array('hostname_pattern', array('{locale}.example.com'), 'getHostnamePattern') + array('schemes', array('https'), 'getSchemes'), + array('methods', array('GET', 'POST'), 'getMethods'), + array('hostname', array('{locale}.example.com'), 'getHostname') ); } } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/namespaceprefix.xml b/src/Symfony/Component/Routing/Tests/Fixtures/namespaceprefix.xml index efc4da9b37..118cf70074 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/namespaceprefix.xml +++ b/src/Symfony/Component/Routing/Tests/Fixtures/namespaceprefix.xml @@ -4,7 +4,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> - + MyBundle:Blog:show \w+ en|fr|de diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml b/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml index 079116399c..198d15d4b7 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml +++ b/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml @@ -4,7 +4,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> - + MyBundle:Blog:show GET \w+ diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml b/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml index 8fad8a0923..4d9f1c474d 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml +++ b/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml @@ -1,7 +1,7 @@ blog_show: - pattern: /blog/{slug} - defaults: { _controller: MyBlogBundle:Blog:show } - hostname_pattern: "{locale}.example.com" - requirements: { '_method': 'GET', 'locale': '\w+' } + pattern: /blog/{slug} + defaults: { _controller: MyBlogBundle:Blog:show } + hostname : "{locale}.example.com" + requirements: { '_method': 'GET', 'locale': '\w+' } options: compiler_class: RouteCompiler diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/validresource.xml b/src/Symfony/Component/Routing/Tests/Fixtures/validresource.xml index b3747864fb..803d8f2eed 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/validresource.xml +++ b/src/Symfony/Component/Routing/Tests/Fixtures/validresource.xml @@ -4,7 +4,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> - + 123 \d+ diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/validresource.yml b/src/Symfony/Component/Routing/Tests/Fixtures/validresource.yml index 35a45398ff..b1de7ebbfc 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/validresource.yml +++ b/src/Symfony/Component/Routing/Tests/Fixtures/validresource.yml @@ -1,7 +1,7 @@ blog_show: - resource: validpattern.yml - prefix: /{foo} - defaults: { 'foo': '123' } - requirements: { 'foo': '\d+' } - options: { 'foo': 'bar' } - hostname_pattern: "{locale}.example.com" + resource: validpattern.yml + prefix: /{foo} + defaults: { 'foo': '123' } + requirements: { 'foo': '\d+' } + options: { 'foo': 'bar' } + hostname: "{locale}.example.com" diff --git a/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php index 9f5597541b..31c43f58c6 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php @@ -89,10 +89,12 @@ class AnnotationClassLoaderTest extends AbstractAnnotationLoaderTest { $routeDatas = array_replace(array( 'name' => 'route', - 'pattern' => '/', + 'path' => '/', 'requirements' => array(), 'options' => array(), 'defaults' => array(), + 'schemes' => array(), + 'methods' => array(), ), $routeDatas); $this->reader @@ -103,7 +105,7 @@ class AnnotationClassLoaderTest extends AbstractAnnotationLoaderTest $routeCollection = $this->loader->load($className); $route = $routeCollection->get($routeDatas['name']); - $this->assertSame($routeDatas['pattern'], $route->getPattern(), '->load preserves pattern annotation'); + $this->assertSame($routeDatas['path'], $route->getPath(), '->load preserves path annotation'); $this->assertSame($routeDatas['requirements'],$route->getRequirements(), '->load preserves requirements annotation'); $this->assertCount(0, array_intersect($route->getOptions(), $routeDatas['options']), '->load preserves options annotation'); $this->assertSame(array_replace($routeDatas['defaults'], $methodArgs), $route->getDefaults(), '->load preserves defaults annotation'); diff --git a/src/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php index 3ff425d981..109ade1183 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php @@ -43,10 +43,10 @@ class PhpFileLoaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals(1, count($routes), 'One route is loaded'); $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes); $route = $routes['blog_show']; - $this->assertEquals('/blog/{slug}', $route->getPattern()); + $this->assertEquals('/blog/{slug}', $route->getPath()); $this->assertEquals('MyBlogBundle:Blog:show', $route->getDefault('_controller')); $this->assertEquals('GET', $route->getRequirement('_method')); - $this->assertEquals('{locale}.example.com', $route->getHostnamePattern()); + $this->assertEquals('{locale}.example.com', $route->getHostname()); $this->assertEquals('RouteCompiler', $route->getOption('compiler_class')); } } diff --git a/src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php index 17e33ef297..04379a80c7 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php @@ -44,11 +44,11 @@ class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals(1, count($routes), 'One route is loaded'); $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes); $route = $routes['blog_show']; - $this->assertEquals('/blog/{slug}', $route->getPattern()); + $this->assertEquals('/blog/{slug}', $route->getPath()); $this->assertEquals('MyBundle:Blog:show', $route->getDefault('_controller')); $this->assertEquals('GET', $route->getRequirement('_method')); $this->assertEquals('\w+', $route->getRequirement('locale')); - $this->assertEquals('{locale}.example.com', $route->getHostnamePattern()); + $this->assertEquals('{locale}.example.com', $route->getHostname()); $this->assertEquals('RouteCompiler', $route->getOption('compiler_class')); } @@ -59,11 +59,11 @@ class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase $this->assertCount(1, $routeCollection, 'One route is loaded'); $route = $routeCollection->get('blog_show'); - $this->assertEquals('/blog/{slug}', $route->getPattern()); + $this->assertEquals('/blog/{slug}', $route->getPath()); $this->assertEquals('MyBundle:Blog:show', $route->getDefault('_controller')); $this->assertEquals('\w+', $route->getRequirement('slug')); $this->assertEquals('en|fr|de', $route->getRequirement('_locale')); - $this->assertEquals('{_locale}.example.com', $route->getHostnamePattern()); + $this->assertEquals('{_locale}.example.com', $route->getHostname()); $this->assertEquals('RouteCompiler', $route->getOption('compiler_class')); } @@ -75,12 +75,12 @@ class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals(1, count($routes), 'One route is loaded'); $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes); - $this->assertEquals('/{foo}/blog/{slug}', $routes['blog_show']->getPattern()); + $this->assertEquals('/{foo}/blog/{slug}', $routes['blog_show']->getPath()); $this->assertEquals('MyBundle:Blog:show', $routes['blog_show']->getDefault('_controller')); $this->assertEquals('123', $routes['blog_show']->getDefault('foo')); $this->assertEquals('\d+', $routes['blog_show']->getRequirement('foo')); $this->assertEquals('bar', $routes['blog_show']->getOption('foo')); - $this->assertEquals('{locale}.example.com', $routes['blog_show']->getHostnamePattern()); + $this->assertEquals('{locale}.example.com', $routes['blog_show']->getHostname()); } /** diff --git a/src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php index f99e789486..e7af00de24 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php @@ -70,7 +70,7 @@ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase $route = $routeCollection->get('#$péß^a|'); $this->assertInstanceOf('Symfony\Component\Routing\Route', $route); - $this->assertSame('/true', $route->getPattern()); + $this->assertSame('/true', $route->getPath()); } public function testLoadWithPattern() @@ -82,11 +82,11 @@ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals(1, count($routes), 'One route is loaded'); $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes); $route = $routes['blog_show']; - $this->assertEquals('/blog/{slug}', $route->getPattern()); + $this->assertEquals('/blog/{slug}', $route->getPath()); $this->assertEquals('MyBlogBundle:Blog:show', $route->getDefault('_controller')); $this->assertEquals('GET', $route->getRequirement('_method')); $this->assertEquals('\w+', $route->getRequirement('locale')); - $this->assertEquals('{locale}.example.com', $route->getHostnamePattern()); + $this->assertEquals('{locale}.example.com', $route->getHostname()); $this->assertEquals('RouteCompiler', $route->getOption('compiler_class')); } @@ -98,11 +98,11 @@ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals(1, count($routes), 'One route is loaded'); $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes); - $this->assertEquals('/{foo}/blog/{slug}', $routes['blog_show']->getPattern()); + $this->assertEquals('/{foo}/blog/{slug}', $routes['blog_show']->getPath()); $this->assertEquals('MyBlogBundle:Blog:show', $routes['blog_show']->getDefault('_controller')); $this->assertEquals('123', $routes['blog_show']->getDefault('foo')); $this->assertEquals('\d+', $routes['blog_show']->getRequirement('foo')); $this->assertEquals('bar', $routes['blog_show']->getOption('foo')); - $this->assertEquals('{locale}.example.com', $routes['blog_show']->getHostnamePattern()); + $this->assertEquals('{locale}.example.com', $routes['blog_show']->getHostname()); } } diff --git a/src/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperPrefixCollectionTest.php b/src/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperPrefixCollectionTest.php index 9ba140bf8c..398798a7d2 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperPrefixCollectionTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperPrefixCollectionTest.php @@ -105,7 +105,7 @@ EOF; $string .= sprintf("%s|-coll %s\n", $prefix, $route->getPrefix()); $string .= $this->collectionToString($route, $prefix.'| '); } else { - $string .= sprintf("%s|-route %s %s\n", $prefix, $route->getName(), $route->getRoute()->getPattern()); + $string .= sprintf("%s|-route %s %s\n", $prefix, $route->getName(), $route->getRoute()->getPath()); } } diff --git a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php index 4cf324151c..d980e4e53a 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php @@ -368,7 +368,7 @@ class UrlMatcherTest extends \PHPUnit_Framework_TestCase $coll = new RouteCollection(); $coll->add('foo', new Route('/foo/{foo}')); $coll->add('bar', new Route('/bar/{foo}', array(), array(), array(), '{locale}.example.net')); - $coll->setHostnamePattern('{locale}.example.com'); + $coll->setHostname('{locale}.example.com'); $matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com')); $this->assertEquals(array('foo' => 'bar', '_route' => 'foo', 'locale' => 'en'), $matcher->match('/foo/bar')); diff --git a/src/Symfony/Component/Routing/Tests/RouteCollectionTest.php b/src/Symfony/Component/Routing/Tests/RouteCollectionTest.php index de1d9b1f39..f0b542c354 100644 --- a/src/Symfony/Component/Routing/Tests/RouteCollectionTest.php +++ b/src/Symfony/Component/Routing/Tests/RouteCollectionTest.php @@ -33,7 +33,7 @@ class RouteCollectionTest extends \PHPUnit_Framework_TestCase $collection->add('foo', new Route('/foo')); $collection->add('foo', new Route('/foo1')); - $this->assertEquals('/foo1', $collection->get('foo')->getPattern()); + $this->assertEquals('/foo1', $collection->get('foo')->getPath()); } public function testDeepOverriddenRoute() @@ -50,8 +50,8 @@ class RouteCollectionTest extends \PHPUnit_Framework_TestCase $collection1->addCollection($collection2); $collection->addCollection($collection1); - $this->assertEquals('/foo2', $collection1->get('foo')->getPattern()); - $this->assertEquals('/foo2', $collection->get('foo')->getPattern()); + $this->assertEquals('/foo2', $collection1->get('foo')->getPath()); + $this->assertEquals('/foo2', $collection->get('foo')->getPath()); } public function testIteratorWithOverriddenRoutes() @@ -63,7 +63,7 @@ class RouteCollectionTest extends \PHPUnit_Framework_TestCase $collection1->add('foo', new Route('/foo1')); $collection->addCollection($collection1); - $this->assertEquals('/foo1', $this->getFirstNamedRoute($collection, 'foo')->getPattern()); + $this->assertEquals('/foo1', $this->getFirstNamedRoute($collection, 'foo')->getPath()); } public function testCount() @@ -110,7 +110,7 @@ class RouteCollectionTest extends \PHPUnit_Framework_TestCase $collection1 = new RouteCollection(); $collection1->add('foo', $foo1 = new Route('/foo1')); $collection->addCollection($collection1, '/{foo}', array('foo' => 'foo'), array('foo' => '\d+'), array('foo' => 'bar')); - $this->assertEquals('/{foo}/foo1', $collection->get('foo')->getPattern(), '->addCollection() can add a prefix to all merged routes'); + $this->assertEquals('/{foo}/foo1', $collection->get('foo')->getPath(), '->addCollection() can add a prefix to all merged routes'); $this->assertEquals(array('foo' => 'foo'), $collection->get('foo')->getDefaults(), '->addCollection() can add a prefix to all merged routes'); $this->assertEquals(array('foo' => '\d+'), $collection->get('foo')->getRequirements(), '->addCollection() can add a prefix to all merged routes'); $this->assertEquals( @@ -137,8 +137,8 @@ class RouteCollectionTest extends \PHPUnit_Framework_TestCase $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')->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('/{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'); @@ -155,8 +155,8 @@ class RouteCollectionTest extends \PHPUnit_Framework_TestCase $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')->getPattern(), 'the route pattern is in synch with the collection prefix'); - $this->assertSame('/ /0/{admin}/bar', $collection->get('bar')->getPattern(), 'the route pattern in a sub-collection is in synch with the collection prefix'); + $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'); } public function testAddPrefixOverridesDefaultsAndRequirements() @@ -224,7 +224,7 @@ class RouteCollectionTest extends \PHPUnit_Framework_TestCase $this->assertNull($collection1->get(0), '->get() does not disclose internal child RouteCollection'); } - public function testSetHostnamePattern() + public function testSetHostname() { $collection = new RouteCollection(); $routea = new Route('/a'); @@ -232,9 +232,9 @@ class RouteCollectionTest extends \PHPUnit_Framework_TestCase $collection->add('a', $routea); $collection->add('b', $routeb); - $collection->setHostnamePattern('{locale}.example.com'); + $collection->setHostname('{locale}.example.com'); - $this->assertEquals('{locale}.example.com', $routea->getHostnamePattern()); - $this->assertEquals('{locale}.example.com', $routeb->getHostnamePattern()); + $this->assertEquals('{locale}.example.com', $routea->getHostname()); + $this->assertEquals('{locale}.example.com', $routeb->getHostname()); } } diff --git a/src/Symfony/Component/Routing/Tests/RouteTest.php b/src/Symfony/Component/Routing/Tests/RouteTest.php index c89ad5d830..954dab41d6 100644 --- a/src/Symfony/Component/Routing/Tests/RouteTest.php +++ b/src/Symfony/Component/Routing/Tests/RouteTest.php @@ -18,25 +18,33 @@ class RouteTest extends \PHPUnit_Framework_TestCase public function testConstructor() { $route = new Route('/{foo}', array('foo' => 'bar'), array('foo' => '\d+'), array('foo' => 'bar'), '{locale}.example.com'); - $this->assertEquals('/{foo}', $route->getPattern(), '__construct() takes a pattern as its first argument'); + $this->assertEquals('/{foo}', $route->getPath(), '__construct() takes a path as its first argument'); $this->assertEquals(array('foo' => 'bar'), $route->getDefaults(), '__construct() takes defaults as its second argument'); $this->assertEquals(array('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->getHostnamePattern(), '__construct() takes a hostname pattern as its fifth argument'); + $this->assertEquals('{locale}.example.com', $route->getHostname(), '__construct() takes a hostname pattern as its fifth argument'); + + $route = new Route('/', array(), array(), array(), '', array('Https'), array('POST', 'put')); + $this->assertEquals(array('https'), $route->getSchemes(), '__construct() takes schemes as its sixth argument and lowercases it'); + $this->assertEquals(array('POST', 'PUT'), $route->getMethods(), '__construct() takes methods as its seventh argument and uppercases it'); + + $route = new Route('/', array(), array(), array(), '', 'Https', 'Post'); + $this->assertEquals(array('https'), $route->getSchemes(), '__construct() takes a single scheme as its sixth argument'); + $this->assertEquals(array('POST'), $route->getMethods(), '__construct() takes a single method as its seventh argument'); } - public function testPattern() + public function testPath() { $route = new Route('/{foo}'); - $route->setPattern('/{bar}'); - $this->assertEquals('/{bar}', $route->getPattern(), '->setPattern() sets the pattern'); - $route->setPattern(''); - $this->assertEquals('/', $route->getPattern(), '->setPattern() adds a / at the beginning of the pattern if needed'); - $route->setPattern('bar'); - $this->assertEquals('/bar', $route->getPattern(), '->setPattern() adds a / at the beginning of the pattern if needed'); - $this->assertEquals($route, $route->setPattern(''), '->setPattern() implements a fluent interface'); - $route->setPattern('//path'); - $this->assertEquals('/path', $route->getPattern(), '->setPattern() does not allow two slashes "//" at the beginning of the pattern as it would be confused with a network path when generating the path from the route'); + $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 slahes "//" 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() @@ -85,7 +93,7 @@ class RouteTest extends \PHPUnit_Framework_TestCase $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(array('foo' => '^\d+$')); - $this->assertEquals('\d+', $route->getRequirement('foo'), '->getRequirement() removes ^ and $ from the pattern'); + $this->assertEquals('\d+', $route->getRequirement('foo'), '->getRequirement() removes ^ and $ from the path'); $this->assertEquals($route, $route->setRequirements(array()), '->setRequirements() implements a fluent interface'); $route->setRequirements(array('foo' => '\d+')); @@ -98,7 +106,7 @@ class RouteTest extends \PHPUnit_Framework_TestCase { $route = new Route('/{foo}'); $route->setRequirement('foo', '^\d+$'); - $this->assertEquals('\d+', $route->getRequirement('foo'), '->setRequirement() removes ^ and $ from the pattern'); + $this->assertEquals('\d+', $route->getRequirement('foo'), '->setRequirement() removes ^ and $ from the path'); } /** @@ -122,11 +130,55 @@ class RouteTest extends \PHPUnit_Framework_TestCase ); } - public function testHostnamePattern() + public function testHostname() { $route = new Route('/'); - $route->setHostnamePattern('{locale}.example.net'); - $this->assertEquals('{locale}.example.net', $route->getHostnamePattern(), '->setHostnamePattern() sets the hostname pattern'); + $route->setHostname('{locale}.example.net'); + $this->assertEquals('{locale}.example.net', $route->getHostname(), '->setHostname() sets the hostname pattern'); + } + + public function testScheme() + { + $route = new Route('/'); + $this->assertEquals(array(), $route->getSchemes(), 'schemes is initialized with array()'); + $route->setSchemes('hTTp'); + $this->assertEquals(array('http'), $route->getSchemes(), '->setSchemes() accepts a single scheme string and lowercases it'); + $route->setSchemes(array('HttpS', 'hTTp')); + $this->assertEquals(array('https', 'http'), $route->getSchemes(), '->setSchemes() accepts an array of schemes and lowercases them'); + } + + public function testSchemeIsBC() + { + $route = new Route('/'); + $route->setRequirement('_scheme', 'http|https'); + $this->assertEquals('http|https', $route->getRequirement('_scheme')); + $this->assertEquals(array('http', 'https'), $route->getSchemes()); + $route->setSchemes(array('hTTp')); + $this->assertEquals('http', $route->getRequirement('_scheme')); + $route->setSchemes(array()); + $this->assertNull($route->getRequirement('_scheme')); + } + + public function testMethod() + { + $route = new Route('/'); + $this->assertEquals(array(), $route->getMethods(), 'methods is initialized with array()'); + $route->setMethods('gEt'); + $this->assertEquals(array('GET'), $route->getMethods(), '->setMethods() accepts a single method string and uppercases it'); + $route->setMethods(array('gEt', 'PosT')); + $this->assertEquals(array('GET', 'POST'), $route->getMethods(), '->setMethods() accepts an array of methods and uppercases them'); + } + + public function testMethodIsBC() + { + $route = new Route('/'); + $route->setRequirement('_method', 'GET|POST'); + $this->assertEquals('GET|POST', $route->getRequirement('_method')); + $this->assertEquals(array('GET', 'POST'), $route->getMethods()); + $route->setMethods(array('gEt')); + $this->assertEquals('GET', $route->getRequirement('_method')); + $route->setMethods(array()); + $this->assertNull($route->getRequirement('_method')); } public function testCompile()