update v 1.0.7.5

This commit is contained in:
Sujit Prasad
2016-06-13 20:41:55 +05:30
parent aa9786d829
commit 283d97e3ea
5078 changed files with 339851 additions and 175995 deletions

View File

@@ -54,22 +54,6 @@ class Route
}
}
/**
* @deprecated Deprecated in 2.2, to be removed in 3.0. Use setPath instead.
*/
public function setPattern($pattern)
{
$this->path = $pattern;
}
/**
* @deprecated Deprecated in 2.2, to be removed in 3.0. Use getPath instead.
*/
public function getPattern()
{
return $this->path;
}
public function setPath($path)
{
$this->path = $path;

View File

@@ -1,6 +1,13 @@
CHANGELOG
=========
2.8.0
-----
* allowed specifying a directory to recursively load all routing configuration files it contains
* Added ObjectRouteLoader and ServiceRouteLoader that allow routes to be loaded
by calling a method on an object/service.
2.5.0
-----

View File

@@ -15,8 +15,6 @@ namespace Symfony\Component\Routing\Exception;
* ExceptionInterface.
*
* @author Alexandre Salomé <alexandre.salome@gmail.com>
*
* @api
*/
interface ExceptionInterface
{

View File

@@ -15,8 +15,6 @@ namespace Symfony\Component\Routing\Exception;
* Exception thrown when a parameter is not valid.
*
* @author Alexandre Salomé <alexandre.salome@gmail.com>
*
* @api
*/
class InvalidParameterException extends \InvalidArgumentException implements ExceptionInterface
{

View File

@@ -17,8 +17,6 @@ namespace Symfony\Component\Routing\Exception;
* This exception should trigger an HTTP 405 response in your application code.
*
* @author Kris Wallsmith <kris@symfony.com>
*
* @api
*/
class MethodNotAllowedException extends \RuntimeException implements ExceptionInterface
{

View File

@@ -16,8 +16,6 @@ namespace Symfony\Component\Routing\Exception;
* mandatory parameters.
*
* @author Alexandre Salomé <alexandre.salome@gmail.com>
*
* @api
*/
class MissingMandatoryParametersException extends \InvalidArgumentException implements ExceptionInterface
{

View File

@@ -17,8 +17,6 @@ namespace Symfony\Component\Routing\Exception;
* This exception should trigger an HTTP 404 response in your application code.
*
* @author Kris Wallsmith <kris@symfony.com>
*
* @api
*/
class ResourceNotFoundException extends \RuntimeException implements ExceptionInterface
{

View File

@@ -15,8 +15,6 @@ namespace Symfony\Component\Routing\Exception;
* Exception thrown when a route does not exist.
*
* @author Alexandre Salomé <alexandre.salome@gmail.com>
*
* @api
*/
class RouteNotFoundException extends \InvalidArgumentException implements ExceptionInterface
{

View File

@@ -17,8 +17,6 @@ use Symfony\Component\Routing\RouteCollection;
* GeneratorDumperInterface is the interface that all generator dumper classes must implement.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
interface GeneratorDumperInterface
{

View File

@@ -16,8 +16,6 @@ namespace Symfony\Component\Routing\Generator\Dumper;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Tobias Schultze <http://tobion.de>
*
* @api
*/
class PhpGeneratorDumper extends GeneratorDumper
{
@@ -32,8 +30,6 @@ class PhpGeneratorDumper extends GeneratorDumper
* @param array $options An array of options
*
* @return string A PHP class representing the generator class
*
* @api
*/
public function dump(array $options = array())
{
@@ -57,7 +53,7 @@ use Psr\Log\LoggerInterface;
*/
class {$options['class']} extends {$options['base_class']}
{
private static \$declaredRoutes = {$this->generateDeclaredRoutes()};
private static \$declaredRoutes;
/**
* Constructor.
@@ -66,6 +62,9 @@ class {$options['class']} extends {$options['base_class']}
{
\$this->context = \$context;
\$this->logger = \$logger;
if (null === self::\$declaredRoutes) {
self::\$declaredRoutes = {$this->generateDeclaredRoutes()};
}
}
{$this->generateGenerateMethod()}
@@ -108,16 +107,16 @@ EOF;
*/
private function generateGenerateMethod()
{
return <<<EOF
public function generate(\$name, \$parameters = array(), \$referenceType = self::ABSOLUTE_PATH)
return <<<'EOF'
public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
{
if (!isset(self::\$declaredRoutes[\$name])) {
throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', \$name));
if (!isset(self::$declaredRoutes[$name])) {
throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name));
}
list(\$variables, \$defaults, \$requirements, \$tokens, \$hostTokens, \$requiredSchemes) = self::\$declaredRoutes[\$name];
list($variables, $defaults, $requirements, $tokens, $hostTokens, $requiredSchemes) = self::$declaredRoutes[$name];
return \$this->doGenerate(\$variables, \$defaults, \$requirements, \$tokens, \$parameters, \$name, \$referenceType, \$hostTokens, \$requiredSchemes);
return $this->doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens, $requiredSchemes);
}
EOF;
}

View File

@@ -24,8 +24,6 @@ use Psr\Log\LoggerInterface;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Tobias Schultze <http://tobion.de>
*
* @api
*/
class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInterface
{
@@ -83,8 +81,6 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt
* @param RouteCollection $routes A RouteCollection instance
* @param RequestContext $context The context
* @param LoggerInterface|null $logger A logger instance
*
* @api
*/
public function __construct(RouteCollection $routes, RequestContext $context, LoggerInterface $logger = null)
{
@@ -206,23 +202,10 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt
$scheme = $this->context->getScheme();
if ($requiredSchemes) {
$schemeMatched = false;
foreach ($requiredSchemes as $requiredScheme) {
if ($scheme === $requiredScheme) {
$schemeMatched = true;
break;
}
}
if (!$schemeMatched) {
if (!in_array($scheme, $requiredSchemes, true)) {
$referenceType = self::ABSOLUTE_URL;
$scheme = current($requiredSchemes);
}
} elseif (isset($requirements['_scheme']) && ($req = strtolower($requirements['_scheme'])) && $scheme !== $req) {
// We do this for BC; to be removed if _scheme is not supported anymore
$referenceType = self::ABSOLUTE_URL;
$scheme = $req;
}
if ($hostTokens) {
@@ -277,7 +260,10 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt
}
// add a query string if needed
$extra = array_diff_key($parameters, $variables, $defaults);
$extra = array_udiff_assoc(array_diff_key($parameters, $variables), $defaults, function ($a, $b) {
return $a == $b ? 0 : 1;
});
if ($extra && $query = http_build_query($extra, '', '&')) {
// "/" and "?" can be left decoded for better user experience, see
// http://tools.ietf.org/html/rfc3986#section-3.4

View File

@@ -28,33 +28,31 @@ use Symfony\Component\Routing\RequestContextAwareInterface;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Tobias Schultze <http://tobion.de>
*
* @api
*/
interface UrlGeneratorInterface extends RequestContextAwareInterface
{
/**
* Generates an absolute URL, e.g. "http://example.com/dir/file".
*/
const ABSOLUTE_URL = true;
const ABSOLUTE_URL = 0;
/**
* Generates an absolute path, e.g. "/dir/file".
*/
const ABSOLUTE_PATH = false;
const ABSOLUTE_PATH = 1;
/**
* Generates a relative path based on the current request path, e.g. "../parent-file".
*
* @see UrlGenerator::getRelativePath()
*/
const RELATIVE_PATH = 'relative';
const RELATIVE_PATH = 2;
/**
* Generates a network path, e.g. "//example.com/dir/file".
* Such reference reuses the current scheme but specifies the host.
*/
const NETWORK_PATH = 'network';
const NETWORK_PATH = 3;
/**
* Generates a URL or path for a specific route based on the given parameters.
@@ -71,9 +69,9 @@ interface UrlGeneratorInterface extends RequestContextAwareInterface
*
* If there is no route with the given name, the generator must throw the RouteNotFoundException.
*
* @param string $name The name of the route
* @param mixed $parameters An array of parameters
* @param bool|string $referenceType The type of reference to be generated (one of the constants)
* @param string $name The name of the route
* @param mixed $parameters An array of parameters
* @param int $referenceType The type of reference to be generated (one of the constants)
*
* @return string The generated URL
*
@@ -81,8 +79,6 @@ interface UrlGeneratorInterface extends RequestContextAwareInterface
* @throws MissingMandatoryParametersException When some parameters are missing that are mandatory for the route
* @throws InvalidParameterException When a parameter value for a placeholder is not correct because
* it does not match the requirement
*
* @api
*/
public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH);
}

View File

@@ -1,4 +1,4 @@
Copyright (c) 2004-2015 Fabien Potencier
Copyright (c) 2004-2016 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -110,7 +110,7 @@ abstract class AnnotationClassLoader implements LoaderInterface
$class = new \ReflectionClass($class);
if ($class->isAbstract()) {
throw new \InvalidArgumentException(sprintf('Annotations from class "%s" cannot be read as it is abstract.', $class));
throw new \InvalidArgumentException(sprintf('Annotations from class "%s" cannot be read as it is abstract.', $class->getName()));
}
$globals = $this->getGlobals($class);
@@ -139,14 +139,14 @@ abstract class AnnotationClassLoader implements LoaderInterface
$defaults = array_replace($globals['defaults'], $annot->getDefaults());
foreach ($method->getParameters() as $param) {
if (!isset($defaults[$param->getName()]) && $param->isOptional()) {
if (!isset($defaults[$param->getName()]) && $param->isDefaultValueAvailable()) {
$defaults[$param->getName()] = $param->getDefaultValue();
}
}
$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());
$schemes = array_merge($globals['schemes'], $annot->getSchemes());
$methods = array_merge($globals['methods'], $annot->getMethods());
$host = $annot->getHost();
if (null === $host) {
@@ -220,11 +220,8 @@ abstract class AnnotationClassLoader implements LoaderInterface
);
if ($annot = $this->reader->getClassAnnotation($class, $this->routeAnnotationClass)) {
// for BC reasons
if (null !== $annot->getPath()) {
$globals['path'] = $annot->getPath();
} elseif (null !== $annot->getPattern()) {
$globals['path'] = $annot->getPattern();
}
if (null !== $annot->getRequirements()) {

View File

@@ -66,12 +66,16 @@ class AnnotationDirectoryLoader extends AnnotationFileLoader
*/
public function supports($resource, $type = null)
{
if (!is_string($resource)) {
return false;
}
try {
$path = $this->locator->locate($resource);
} catch (\Exception $e) {
return false;
}
return is_string($resource) && is_dir($path) && (!$type || 'annotation' === $type);
return is_dir($path) && (!$type || 'annotation' === $type);
}
}

View File

@@ -64,6 +64,10 @@ class AnnotationFileLoader extends FileLoader
$collection->addResource(new FileResource($path));
$collection->addCollection($this->loader->load($class, $type));
}
if (PHP_VERSION_ID >= 70000) {
// PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
gc_mem_caches();
}
return $collection;
}
@@ -88,10 +92,10 @@ class AnnotationFileLoader extends FileLoader
$class = false;
$namespace = false;
$tokens = token_get_all(file_get_contents($file));
for ($i = 0, $count = count($tokens); $i < $count; ++$i) {
for ($i = 0; isset($tokens[$i]); ++$i) {
$token = $tokens[$i];
if (!is_array($token)) {
if (!isset($token[1])) {
continue;
}
@@ -100,15 +104,32 @@ class AnnotationFileLoader extends FileLoader
}
if (true === $namespace && T_STRING === $token[0]) {
$namespace = '';
do {
$namespace .= $token[1];
$token = $tokens[++$i];
} while ($i < $count && is_array($token) && in_array($token[0], array(T_NS_SEPARATOR, T_STRING)));
$namespace = $token[1];
while (isset($tokens[++$i][1]) && in_array($tokens[$i][0], array(T_NS_SEPARATOR, T_STRING))) {
$namespace .= $tokens[$i][1];
}
$token = $tokens[$i];
}
if (T_CLASS === $token[0]) {
$class = true;
// Skip usage of ::class constant
$isClassConstant = false;
for ($j = $i - 1; $j > 0; --$j) {
if (!isset($tokens[$j][1])) {
break;
}
if (T_DOUBLE_COLON === $tokens[$j][0]) {
$isClassConstant = true;
break;
} elseif (!in_array($tokens[$j][0], array(T_WHITESPACE, T_DOC_COMMENT, T_COMMENT))) {
break;
}
}
if (!$isClassConstant) {
$class = true;
}
}
if (T_NAMESPACE === $token[0]) {

View File

@@ -20,8 +20,6 @@ use Symfony\Component\Routing\RouteCollection;
* The Closure must return a RouteCollection instance.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class ClosureLoader extends Loader
{
@@ -32,8 +30,6 @@ class ClosureLoader extends Loader
* @param string|null $type The resource type
*
* @return RouteCollection A RouteCollection instance
*
* @api
*/
public function load($closure, $type = null)
{
@@ -42,8 +38,6 @@ class ClosureLoader extends Loader
/**
* {@inheritdoc}
*
* @api
*/
public function supports($resource, $type = null)
{

View File

@@ -0,0 +1,40 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Routing\Loader\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Routing\Loader\ObjectRouteLoader;
/**
* A route loader that executes a service to load the routes.
*
* This depends on the DependencyInjection component.
*
* @author Ryan Weaver <ryan@knpuniversity.com>
*/
class ServiceRouterLoader extends ObjectRouteLoader
{
/**
* @var ContainerInterface
*/
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
protected function getServiceObject($id)
{
return $this->container->get($id);
}
}

View File

@@ -0,0 +1,58 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Routing\Loader;
use Symfony\Component\Config\Loader\FileLoader;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Config\Resource\DirectoryResource;
class DirectoryLoader extends FileLoader
{
/**
* {@inheritdoc}
*/
public function load($file, $type = null)
{
$path = $this->locator->locate($file);
$collection = new RouteCollection();
$collection->addResource(new DirectoryResource($path));
foreach (scandir($path) as $dir) {
if ('.' !== $dir[0]) {
$this->setCurrentDir($path);
$subPath = $path.'/'.$dir;
$subType = null;
if (is_dir($subPath)) {
$subPath .= '/';
$subType = 'directory';
}
$subCollection = $this->import($subPath, $subType, false, $path);
$collection->addCollection($subCollection);
}
}
return $collection;
}
/**
* {@inheritdoc}
*/
public function supports($resource, $type = null)
{
// only when type is forced to directory, not to conflict with AnnotationLoader
return 'directory' === $type;
}
}

View File

@@ -0,0 +1,95 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Routing\Loader;
use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Routing\RouteCollection;
/**
* A route loader that calls a method on an object to load the routes.
*
* @author Ryan Weaver <ryan@knpuniversity.com>
*/
abstract class ObjectRouteLoader extends Loader
{
/**
* Returns the object that the method will be called on to load routes.
*
* For example, if your application uses a service container,
* the $id may be a service id.
*
* @param string $id
*
* @return object
*/
abstract protected function getServiceObject($id);
/**
* Calls the service that will load the routes.
*
* @param mixed $resource Some value that will resolve to a callable
* @param string|null $type The resource type
*
* @return RouteCollection
*/
public function load($resource, $type = null)
{
$parts = explode(':', $resource);
if (count($parts) != 2) {
throw new \InvalidArgumentException(sprintf('Invalid resource "%s" passed to the "service" route loader: use the format "service_name:methodName"', $resource));
}
$serviceString = $parts[0];
$method = $parts[1];
$loaderObject = $this->getServiceObject($serviceString);
if (!is_object($loaderObject)) {
throw new \LogicException(sprintf('%s:getServiceObject() must return an object: %s returned', get_class($this), gettype($loaderObject)));
}
if (!method_exists($loaderObject, $method)) {
throw new \BadMethodCallException(sprintf('Method "%s" not found on "%s" when importing routing resource "%s"', $method, get_class($loaderObject), $resource));
}
$routeCollection = call_user_func(array($loaderObject, $method), $this);
if (!$routeCollection instanceof RouteCollection) {
$type = is_object($routeCollection) ? get_class($routeCollection) : gettype($routeCollection);
throw new \LogicException(sprintf('The %s::%s method must return a RouteCollection: %s returned', get_class($loaderObject), $method, $type));
}
// make the service file tracked so that if it changes, the cache rebuilds
$this->addClassResource(new \ReflectionClass($loaderObject), $routeCollection);
return $routeCollection;
}
/**
* {@inheritdoc}
*/
public function supports($resource, $type = null)
{
return 'service' === $type;
}
private function addClassResource(\ReflectionClass $class, RouteCollection $collection)
{
do {
if (is_file($class->getFileName())) {
$collection->addResource(new FileResource($class->getFileName()));
}
} while ($class = $class->getParentClass());
}
}

View File

@@ -21,8 +21,6 @@ use Symfony\Component\Routing\RouteCollection;
* The file must return a RouteCollection instance.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class PhpFileLoader extends FileLoader
{
@@ -33,8 +31,6 @@ class PhpFileLoader extends FileLoader
* @param string|null $type The resource type
*
* @return RouteCollection A RouteCollection instance
*
* @api
*/
public function load($file, $type = null)
{
@@ -49,8 +45,6 @@ class PhpFileLoader extends FileLoader
/**
* {@inheritdoc}
*
* @api
*/
public function supports($resource, $type = null)
{

View File

@@ -22,8 +22,6 @@ use Symfony\Component\Config\Util\XmlUtils;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Tobias Schultze <http://tobion.de>
*
* @api
*/
class XmlFileLoader extends FileLoader
{
@@ -40,8 +38,6 @@ class XmlFileLoader extends FileLoader
*
* @throws \InvalidArgumentException When the file cannot be loaded or when the XML cannot be
* parsed because it does not validate against the scheme.
*
* @api
*/
public function load($file, $type = null)
{
@@ -94,8 +90,6 @@ class XmlFileLoader extends FileLoader
/**
* {@inheritdoc}
*
* @api
*/
public function supports($resource, $type = null)
{
@@ -113,19 +107,10 @@ class XmlFileLoader extends FileLoader
*/
protected function parseRoute(RouteCollection $collection, \DOMElement $node, $path)
{
if ('' === ($id = $node->getAttribute('id')) || (!$node->hasAttribute('pattern') && !$node->hasAttribute('path'))) {
if ('' === ($id = $node->getAttribute('id')) || !$node->hasAttribute('path')) {
throw new \InvalidArgumentException(sprintf('The <route> 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 <route> 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 = preg_split('/[\s,\|]++/', $node->getAttribute('schemes'), -1, PREG_SPLIT_NO_EMPTY);
$methods = preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, PREG_SPLIT_NO_EMPTY);

View File

@@ -14,6 +14,7 @@ namespace Symfony\Component\Routing\Loader;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Parser as YamlParser;
use Symfony\Component\Config\Loader\FileLoader;
@@ -22,13 +23,11 @@ use Symfony\Component\Config\Loader\FileLoader;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Tobias Schultze <http://tobion.de>
*
* @api
*/
class YamlFileLoader extends FileLoader
{
private static $availableKeys = array(
'resource', 'type', 'prefix', 'pattern', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition',
'resource', 'type', 'prefix', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition',
);
private $yamlParser;
@@ -41,8 +40,6 @@ class YamlFileLoader extends FileLoader
* @return RouteCollection A RouteCollection instance
*
* @throws \InvalidArgumentException When a route can't be parsed because YAML is invalid
*
* @api
*/
public function load($file, $type = null)
{
@@ -60,31 +57,26 @@ class YamlFileLoader extends FileLoader
$this->yamlParser = new YamlParser();
}
$config = $this->yamlParser->parse(file_get_contents($path));
try {
$parsedConfig = $this->yamlParser->parse(file_get_contents($path));
} catch (ParseException $e) {
throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML.', $path), 0, $e);
}
$collection = new RouteCollection();
$collection->addResource(new FileResource($path));
// empty file
if (null === $config) {
if (null === $parsedConfig) {
return $collection;
}
// not an array
if (!is_array($config)) {
if (!is_array($parsedConfig)) {
throw new \InvalidArgumentException(sprintf('The file "%s" must contain a YAML array.', $path));
}
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']);
}
foreach ($parsedConfig as $name => $config) {
$this->validate($config, $name, $path);
if (isset($config['resource'])) {
@@ -99,8 +91,6 @@ class YamlFileLoader extends FileLoader
/**
* {@inheritdoc}
*
* @api
*/
public function supports($resource, $type = null)
{

View File

@@ -37,8 +37,7 @@
<xsd:group ref="configs" minOccurs="0" maxOccurs="unbounded" />
<xsd:attribute name="id" type="xsd:string" use="required" />
<xsd:attribute name="path" type="xsd:string" />
<xsd:attribute name="pattern" type="xsd:string" />
<xsd:attribute name="path" type="xsd:string" use="required" />
<xsd:attribute name="host" type="xsd:string" />
<xsd:attribute name="schemes" type="xsd:string" />
<xsd:attribute name="methods" type="xsd:string" />

View File

@@ -15,6 +15,8 @@ namespace Symfony\Component\Routing\Matcher\Dumper;
* Collection of routes.
*
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
*
* @internal
*/
class DumperCollection implements \IteratorAggregate
{

View File

@@ -15,6 +15,8 @@ namespace Symfony\Component\Routing\Matcher\Dumper;
* Prefix tree of routes preserving routes order.
*
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
*
* @internal
*/
class DumperPrefixCollection extends DumperCollection
{

View File

@@ -17,6 +17,8 @@ use Symfony\Component\Routing\Route;
* Container for a Route.
*
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
*
* @internal
*/
class DumperRoute
{

View File

@@ -215,14 +215,11 @@ EOF;
$hasTrailingSlash = false;
$matches = false;
$hostMatches = false;
$methods = array();
$methods = $route->getMethods();
if ($req = $route->getRequirement('_method')) {
$methods = explode('|', strtoupper($req));
// GET and HEAD are equivalent
if (in_array('GET', $methods) && !in_array('HEAD', $methods)) {
$methods[] = 'HEAD';
}
// GET and HEAD are equivalent
if (in_array('GET', $methods) && !in_array('HEAD', $methods)) {
$methods[] = 'HEAD';
}
$supportsTrailingSlash = $supportsRedirections && (!$methods || in_array('HEAD', $methods));

View File

@@ -16,8 +16,6 @@ use Symfony\Component\Routing\Route;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
abstract class RedirectableUrlMatcher extends UrlMatcher implements RedirectableUrlMatcherInterface
{

View File

@@ -15,8 +15,6 @@ namespace Symfony\Component\Routing\Matcher;
* RedirectableUrlMatcherInterface knows how to redirect the user.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
interface RedirectableUrlMatcherInterface
{
@@ -28,8 +26,6 @@ interface RedirectableUrlMatcherInterface
* @param string|null $scheme The URL scheme (null to keep the current one)
*
* @return array An array of parameters
*
* @api
*/
public function redirect($path, $route, $scheme = null);
}

View File

@@ -11,6 +11,7 @@
namespace Symfony\Component\Routing\Matcher;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Exception\ExceptionInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
@@ -40,6 +41,15 @@ class TraceableUrlMatcher extends UrlMatcher
return $this->traces;
}
public function getTracesForRequest(Request $request)
{
$this->request = $request;
$traces = $this->getTraces($request->getPathInfo());
$this->request = null;
return $traces;
}
protected function matchCollection($pathinfo, RouteCollection $routes)
{
foreach ($routes as $name => $route) {
@@ -78,16 +88,16 @@ class TraceableUrlMatcher extends UrlMatcher
}
// check HTTP method requirement
if ($req = $route->getRequirement('_method')) {
if ($requiredMethods = $route->getMethods()) {
// HEAD and GET are equivalent as per RFC
if ('HEAD' === $method = $this->context->getMethod()) {
$method = 'GET';
}
if (!in_array($method, $req = explode('|', strtoupper($req)))) {
$this->allow = array_merge($this->allow, $req);
if (!in_array($method, $requiredMethods)) {
$this->allow = array_merge($this->allow, $requiredMethods);
$this->addTrace(sprintf('Method "%s" does not match the requirement ("%s")', $this->context->getMethod(), implode(', ', $req)), self::ROUTE_ALMOST_MATCHES, $name, $route);
$this->addTrace(sprintf('Method "%s" does not match any of the required methods (%s)', $this->context->getMethod(), implode(', ', $requiredMethods)), self::ROUTE_ALMOST_MATCHES, $name, $route);
continue;
}
@@ -107,7 +117,7 @@ class TraceableUrlMatcher extends UrlMatcher
$scheme = $this->context->getScheme();
if (!$route->hasScheme($scheme)) {
$this->addTrace(sprintf('Scheme "%s" does not match any of the required schemes ("%s"); the user will be redirected to first required scheme', $scheme, implode(', ', $requiredSchemes)), self::ROUTE_ALMOST_MATCHES, $name, $route);
$this->addTrace(sprintf('Scheme "%s" does not match any of the required schemes (%s); the user will be redirected to first required scheme', $scheme, implode(', ', $requiredSchemes)), self::ROUTE_ALMOST_MATCHES, $name, $route);
return true;
}

View File

@@ -24,8 +24,6 @@ use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
* UrlMatcher matches URL based on a set of routes.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface
{
@@ -61,8 +59,6 @@ class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface
*
* @param RouteCollection $routes A RouteCollection instance
* @param RequestContext $context The context
*
* @api
*/
public function __construct(RouteCollection $routes, RequestContext $context)
{
@@ -98,7 +94,7 @@ class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface
}
throw 0 < count($this->allow)
? new MethodNotAllowedException(array_unique(array_map('strtoupper', $this->allow)))
? new MethodNotAllowedException(array_unique($this->allow))
: new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo));
}
@@ -152,14 +148,14 @@ class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface
}
// check HTTP method requirement
if ($req = $route->getRequirement('_method')) {
if ($requiredMethods = $route->getMethods()) {
// HEAD and GET are equivalent as per RFC
if ('HEAD' === $method = $this->context->getMethod()) {
$method = 'GET';
}
if (!in_array($method, $req = explode('|', strtoupper($req)))) {
$this->allow = array_merge($this->allow, $req);
if (!in_array($method, $requiredMethods)) {
$this->allow = array_merge($this->allow, $requiredMethods);
continue;
}

View File

@@ -19,8 +19,6 @@ use Symfony\Component\Routing\Exception\MethodNotAllowedException;
* UrlMatcherInterface is the interface that all URL matcher classes must implement.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
interface UrlMatcherInterface extends RequestContextAwareInterface
{
@@ -36,8 +34,6 @@ interface UrlMatcherInterface extends RequestContextAwareInterface
*
* @throws ResourceNotFoundException If the resource could not be found
* @throws MethodNotAllowedException If the resource was found but the request method is not allowed
*
* @api
*/
public function match($pathinfo);
}

13
vendor/symfony/routing/README.md vendored Normal file
View File

@@ -0,0 +1,13 @@
Routing Component
=================
The Routing component maps an HTTP request to a set of configuration variables.
Resources
---------
* [Documentation](https://symfony.com/doc/current/components/routing/index.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)

View File

@@ -20,8 +20,6 @@ use Symfony\Component\HttpFoundation\Request;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Tobias Schultze <http://tobion.de>
*
* @api
*/
class RequestContext
{
@@ -50,8 +48,6 @@ class RequestContext
* @param int $httpsPort The HTTPS port
* @param string $path The path
* @param string $queryString The query string
*
* @api
*/
public function __construct($baseUrl = '', $method = 'GET', $host = 'localhost', $scheme = 'http', $httpPort = 80, $httpsPort = 443, $path = '/', $queryString = '')
{
@@ -102,8 +98,6 @@ class RequestContext
* @param string $baseUrl The base URL
*
* @return RequestContext The current instance, implementing a fluent interface
*
* @api
*/
public function setBaseUrl($baseUrl)
{
@@ -154,8 +148,6 @@ class RequestContext
* @param string $method The HTTP method
*
* @return RequestContext The current instance, implementing a fluent interface
*
* @api
*/
public function setMethod($method)
{
@@ -182,8 +174,6 @@ class RequestContext
* @param string $host The HTTP host
*
* @return RequestContext The current instance, implementing a fluent interface
*
* @api
*/
public function setHost($host)
{
@@ -208,8 +198,6 @@ class RequestContext
* @param string $scheme The HTTP scheme
*
* @return RequestContext The current instance, implementing a fluent interface
*
* @api
*/
public function setScheme($scheme)
{
@@ -234,8 +222,6 @@ class RequestContext
* @param int $httpPort The HTTP port
*
* @return RequestContext The current instance, implementing a fluent interface
*
* @api
*/
public function setHttpPort($httpPort)
{
@@ -260,8 +246,6 @@ class RequestContext
* @param int $httpsPort The HTTPS port
*
* @return RequestContext The current instance, implementing a fluent interface
*
* @api
*/
public function setHttpsPort($httpsPort)
{
@@ -286,8 +270,6 @@ class RequestContext
* @param string $queryString The query string (after "?")
*
* @return RequestContext The current instance, implementing a fluent interface
*
* @api
*/
public function setQueryString($queryString)
{
@@ -352,8 +334,6 @@ class RequestContext
* @param mixed $parameter The parameter value
*
* @return RequestContext The current instance, implementing a fluent interface
*
* @api
*/
public function setParameter($name, $parameter)
{

View File

@@ -11,17 +11,12 @@
namespace Symfony\Component\Routing;
/**
* @api
*/
interface RequestContextAwareInterface
{
/**
* Sets the request context.
*
* @param RequestContext $context The context
*
* @api
*/
public function setContext(RequestContext $context);
@@ -29,8 +24,6 @@ interface RequestContextAwareInterface
* Gets the request context.
*
* @return RequestContext The context
*
* @api
*/
public function getContext();
}

View File

@@ -16,8 +16,6 @@ namespace Symfony\Component\Routing;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Tobias Schultze <http://tobion.de>
*
* @api
*/
class Route implements \Serializable
{
@@ -81,8 +79,6 @@ class Route implements \Serializable
* @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
* @param string $condition A condition that should evaluate to true for the route to match
*
* @api
*/
public function __construct($path, array $defaults = array(), array $requirements = array(), array $options = array(), $host = '', $schemes = array(), $methods = array(), $condition = '')
{
@@ -91,14 +87,8 @@ class Route implements \Serializable
$this->setRequirements($requirements);
$this->setOptions($options);
$this->setHost($host);
// 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);
}
$this->setSchemes($schemes);
$this->setMethods($methods);
$this->setCondition($condition);
}
@@ -142,34 +132,6 @@ class Route implements \Serializable
}
}
/**
* Returns the pattern for the path.
*
* @return string The pattern
*
* @deprecated Deprecated in 2.2, to be removed in 3.0. Use getPath instead.
*/
public function getPattern()
{
return $this->path;
}
/**
* Sets the pattern for the path.
*
* This method implements a fluent interface.
*
* @param string $pattern The path 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.
*
@@ -250,14 +212,6 @@ class Route implements \Serializable
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;
@@ -299,14 +253,6 @@ class Route implements \Serializable
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;
@@ -368,8 +314,6 @@ class Route implements \Serializable
* @param mixed $value The option value
*
* @return Route The current Route instance
*
* @api
*/
public function setOption($name, $value)
{
@@ -479,8 +423,6 @@ class Route implements \Serializable
* @param mixed $default The default value
*
* @return Route The current Route instance
*
* @api
*/
public function setDefault($name, $default)
{
@@ -566,8 +508,6 @@ class Route implements \Serializable
* @param string $regex The regex
*
* @return Route The current Route instance
*
* @api
*/
public function setRequirement($key, $regex)
{
@@ -643,13 +583,6 @@ 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;
}
}

View File

@@ -22,8 +22,6 @@ use Symfony\Component\Config\Resource\ResourceInterface;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Tobias Schultze <http://tobion.de>
*
* @api
*/
class RouteCollection implements \IteratorAggregate, \Countable
{
@@ -73,8 +71,6 @@ class RouteCollection implements \IteratorAggregate, \Countable
*
* @param string $name The route name
* @param Route $route A Route instance
*
* @api
*/
public function add($name, Route $route)
{
@@ -122,8 +118,6 @@ class RouteCollection implements \IteratorAggregate, \Countable
* routes of the added collection.
*
* @param RouteCollection $collection A RouteCollection instance
*
* @api
*/
public function addCollection(RouteCollection $collection)
{
@@ -143,8 +137,6 @@ class RouteCollection implements \IteratorAggregate, \Countable
* @param string $prefix An optional prefix to add before each pattern of the route collection
* @param array $defaults An array of default values
* @param array $requirements An array of requirements
*
* @api
*/
public function addPrefix($prefix, array $defaults = array(), array $requirements = array())
{

View File

@@ -0,0 +1,372 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Routing;
use Symfony\Component\Config\Exception\FileLoaderLoadException;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Config\Resource\ResourceInterface;
/**
* Helps add and import routes into a RouteCollection.
*
* @author Ryan Weaver <ryan@knpuniversity.com>
*/
class RouteCollectionBuilder
{
/**
* @var Route[]|RouteCollectionBuilder[]
*/
private $routes = array();
private $loader;
private $defaults = array();
private $prefix;
private $host;
private $condition;
private $requirements = array();
private $options = array();
private $schemes;
private $methods;
private $resources = array();
/**
* @param LoaderInterface $loader
*/
public function __construct(LoaderInterface $loader = null)
{
$this->loader = $loader;
}
/**
* Import an external routing resource and returns the RouteCollectionBuilder.
*
* $routes->import('blog.yml', '/blog');
*
* @param mixed $resource
* @param string|null $prefix
* @param string $type
*
* @return RouteCollectionBuilder
*
* @throws FileLoaderLoadException
*/
public function import($resource, $prefix = '/', $type = null)
{
/** @var RouteCollection $collection */
$collection = $this->load($resource, $type);
// create a builder from the RouteCollection
$builder = $this->createBuilder();
foreach ($collection->all() as $name => $route) {
$builder->addRoute($route, $name);
}
foreach ($collection->getResources() as $resource) {
$builder->addResource($resource);
}
// mount into this builder
$this->mount($prefix, $builder);
return $builder;
}
/**
* Adds a route and returns it for future modification.
*
* @param string $path The route path
* @param string $controller The route's controller
* @param string|null $name The name to give this route
*
* @return Route
*/
public function add($path, $controller, $name = null)
{
$route = new Route($path);
$route->setDefault('_controller', $controller);
$this->addRoute($route, $name);
return $route;
}
/**
* Returns a RouteCollectionBuilder that can be configured and then added with mount().
*
* @return RouteCollectionBuilder
*/
public function createBuilder()
{
return new self($this->loader);
}
/**
* Add a RouteCollectionBuilder.
*
* @param string $prefix
* @param RouteCollectionBuilder $builder
*/
public function mount($prefix, RouteCollectionBuilder $builder)
{
$builder->prefix = trim(trim($prefix), '/');
$this->routes[] = $builder;
}
/**
* Adds a Route object to the builder.
*
* @param Route $route
* @param string|null $name
*
* @return $this
*/
public function addRoute(Route $route, $name = null)
{
if (null === $name) {
// used as a flag to know which routes will need a name later
$name = '_unnamed_route_'.spl_object_hash($route);
}
$this->routes[$name] = $route;
return $this;
}
/**
* Sets the host on all embedded routes (unless already set).
*
* @param string $pattern
*
* @return $this
*/
public function setHost($pattern)
{
$this->host = $pattern;
return $this;
}
/**
* Sets a condition on all embedded routes (unless already set).
*
* @param string $condition
*
* @return $this
*/
public function setCondition($condition)
{
$this->condition = $condition;
return $this;
}
/**
* Sets a default value that will be added to all embedded routes (unless that
* default value is already set).
*
* @param string $key
* @param mixed $value
*
* @return $this
*/
public function setDefault($key, $value)
{
$this->defaults[$key] = $value;
return $this;
}
/**
* Sets a requirement that will be added to all embedded routes (unless that
* requirement is already set).
*
* @param string $key
* @param mixed $regex
*
* @return $this
*/
public function setRequirement($key, $regex)
{
$this->requirements[$key] = $regex;
return $this;
}
/**
* Sets an opiton that will be added to all embedded routes (unless that
* option is already set).
*
* @param string $key
* @param mixed $value
*
* @return $this
*/
public function setOption($key, $value)
{
$this->options[$key] = $value;
return $this;
}
/**
* Sets the schemes on all embedded routes (unless already set).
*
* @param array|string $schemes
*
* @return $this
*/
public function setSchemes($schemes)
{
$this->schemes = $schemes;
return $this;
}
/**
* Sets the methods on all embedded routes (unless already set).
*
* @param array|string $methods
*
* @return $this
*/
public function setMethods($methods)
{
$this->methods = $methods;
return $this;
}
/**
* Adds a resource for this collection.
*
* @param ResourceInterface $resource
*
* @return $this
*/
private function addResource(ResourceInterface $resource)
{
$this->resources[] = $resource;
return $this;
}
/**
* Creates the final RouteCollection and returns it.
*
* @return RouteCollection
*/
public function build()
{
$routeCollection = new RouteCollection();
foreach ($this->routes as $name => $route) {
if ($route instanceof Route) {
$route->setDefaults(array_merge($this->defaults, $route->getDefaults()));
$route->setOptions(array_merge($this->options, $route->getOptions()));
foreach ($this->requirements as $key => $val) {
if (!$route->hasRequirement($key)) {
$route->setRequirement($key, $val);
}
}
if (null !== $this->prefix) {
$route->setPath('/'.$this->prefix.$route->getPath());
}
if (!$route->getHost()) {
$route->setHost($this->host);
}
if (!$route->getCondition()) {
$route->setCondition($this->condition);
}
if (!$route->getSchemes()) {
$route->setSchemes($this->schemes);
}
if (!$route->getMethods()) {
$route->setMethods($this->methods);
}
// auto-generate the route name if it's been marked
if ('_unnamed_route_' === substr($name, 0, 15)) {
$name = $this->generateRouteName($route);
}
$routeCollection->add($name, $route);
} else {
/* @var self $route */
$subCollection = $route->build();
$subCollection->addPrefix($this->prefix);
$routeCollection->addCollection($subCollection);
}
foreach ($this->resources as $resource) {
$routeCollection->addResource($resource);
}
}
return $routeCollection;
}
/**
* Generates a route name based on details of this route.
*
* @return string
*/
private function generateRouteName(Route $route)
{
$methods = implode('_', $route->getMethods()).'_';
$routeName = $methods.$route->getPath();
$routeName = str_replace(array('/', ':', '|', '-'), '_', $routeName);
$routeName = preg_replace('/[^a-z0-9A-Z_.]+/', '', $routeName);
// Collapse consecutive underscores down into a single underscore.
$routeName = preg_replace('/_+/', '_', $routeName);
return $routeName;
}
/**
* Finds a loader able to load an imported resource and loads it.
*
* @param mixed $resource A resource
* @param string|null $type The resource type or null if unknown
*
* @return RouteCollection
*
* @throws FileLoaderLoadException If no loader is found
*/
private function load($resource, $type = null)
{
if (null === $this->loader) {
throw new \BadMethodCallException('Cannot import other routing resources: you must pass a LoaderInterface when constructing RouteCollectionBuilder.');
}
if ($this->loader->supports($resource, $type)) {
return $this->loader->load($resource, $type);
}
if (null === $resolver = $this->loader->getResolver()) {
throw new FileLoaderLoadException($resource);
}
if (false === $loader = $resolver->resolve($resource, $type)) {
throw new FileLoaderLoadException($resource);
}
return $loader->load($resource, $type);
}
}

View File

@@ -12,7 +12,9 @@
namespace Symfony\Component\Routing;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Config\ConfigCache;
use Symfony\Component\Config\ConfigCacheInterface;
use Symfony\Component\Config\ConfigCacheFactoryInterface;
use Symfony\Component\Config\ConfigCacheFactory;
use Psr\Log\LoggerInterface;
use Symfony\Component\Routing\Generator\ConfigurableRequirementsInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
@@ -71,6 +73,11 @@ class Router implements RouterInterface, RequestMatcherInterface
*/
protected $logger;
/**
* @var ConfigCacheFactoryInterface|null
*/
private $configCacheFactory;
/**
* @var ExpressionFunctionProviderInterface[]
*/
@@ -209,6 +216,16 @@ class Router implements RouterInterface, RequestMatcherInterface
return $this->context;
}
/**
* Sets the ConfigCache factory to use.
*
* @param ConfigCacheFactoryInterface $configCacheFactory The factory to use.
*/
public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory)
{
$this->configCacheFactory = $configCacheFactory;
}
/**
* {@inheritdoc}
*/
@@ -261,27 +278,27 @@ class Router implements RouterInterface, RequestMatcherInterface
return $this->matcher;
}
$class = $this->options['matcher_cache_class'];
$cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']);
if (!$cache->isFresh()) {
$dumper = $this->getMatcherDumperInstance();
if (method_exists($dumper, 'addExpressionLanguageProvider')) {
foreach ($this->expressionLanguageProviders as $provider) {
$dumper->addExpressionLanguageProvider($provider);
$cache = $this->getConfigCacheFactory()->cache($this->options['cache_dir'].'/'.$this->options['matcher_cache_class'].'.php',
function (ConfigCacheInterface $cache) {
$dumper = $this->getMatcherDumperInstance();
if (method_exists($dumper, 'addExpressionLanguageProvider')) {
foreach ($this->expressionLanguageProviders as $provider) {
$dumper->addExpressionLanguageProvider($provider);
}
}
$options = array(
'class' => $this->options['matcher_cache_class'],
'base_class' => $this->options['matcher_base_class'],
);
$cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
}
);
$options = array(
'class' => $class,
'base_class' => $this->options['matcher_base_class'],
);
require_once $cache->getPath();
$cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
}
require_once $cache;
return $this->matcher = new $class($this->context);
return $this->matcher = new $this->options['matcher_cache_class']($this->context);
}
/**
@@ -298,22 +315,22 @@ class Router implements RouterInterface, RequestMatcherInterface
if (null === $this->options['cache_dir'] || null === $this->options['generator_cache_class']) {
$this->generator = new $this->options['generator_class']($this->getRouteCollection(), $this->context, $this->logger);
} else {
$class = $this->options['generator_cache_class'];
$cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']);
if (!$cache->isFresh()) {
$dumper = $this->getGeneratorDumperInstance();
$cache = $this->getConfigCacheFactory()->cache($this->options['cache_dir'].'/'.$this->options['generator_cache_class'].'.php',
function (ConfigCacheInterface $cache) {
$dumper = $this->getGeneratorDumperInstance();
$options = array(
'class' => $class,
'base_class' => $this->options['generator_base_class'],
);
$options = array(
'class' => $this->options['generator_cache_class'],
'base_class' => $this->options['generator_base_class'],
);
$cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
}
$cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
}
);
require_once $cache;
require_once $cache->getPath();
$this->generator = new $class($this->context, $this->logger);
$this->generator = new $this->options['generator_cache_class']($this->context, $this->logger);
}
if ($this->generator instanceof ConfigurableRequirementsInterface) {
@@ -343,4 +360,19 @@ class Router implements RouterInterface, RequestMatcherInterface
{
return new $this->options['matcher_dumper_class']($this->getRouteCollection());
}
/**
* Provides the ConfigCache factory implementation, falling back to a
* default implementation if necessary.
*
* @return ConfigCacheFactoryInterface $configCacheFactory
*/
private function getConfigCacheFactory()
{
if (null === $this->configCacheFactory) {
$this->configCacheFactory = new ConfigCacheFactory($this->options['debug']);
}
return $this->configCacheFactory;
}
}

View File

@@ -1,122 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Routing\Matcher;
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
/**
* ApacheUrlMatcher matches URL based on Apache mod_rewrite matching (see ApacheMatcherDumper).
*
* @deprecated Deprecated since version 2.5, to be removed in 3.0.
* The performance gains are minimal and it's very hard to replicate
* the behavior of PHP implementation.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
*/
class ApacheUrlMatcher extends UrlMatcher
{
/**
* Tries to match a URL based on Apache mod_rewrite matching.
*
* Returns false if no route matches the URL.
*
* @param string $pathinfo The pathinfo to be parsed
*
* @return array An array of parameters
*
* @throws MethodNotAllowedException If the current method is not allowed
*/
public function match($pathinfo)
{
$parameters = array();
$defaults = array();
$allow = array();
$route = null;
foreach ($this->denormalizeValues($_SERVER) as $key => $value) {
$name = $key;
// skip non-routing variables
// this improves performance when $_SERVER contains many usual
// variables like HTTP_*, DOCUMENT_ROOT, REQUEST_URI, ...
if (false === strpos($name, '_ROUTING_')) {
continue;
}
while (0 === strpos($name, 'REDIRECT_')) {
$name = substr($name, 9);
}
// expect _ROUTING_<type>_<name>
// or _ROUTING_<type>
if (0 !== strpos($name, '_ROUTING_')) {
continue;
}
if (false !== $pos = strpos($name, '_', 9)) {
$type = substr($name, 9, $pos - 9);
$name = substr($name, $pos + 1);
} else {
$type = substr($name, 9);
}
if ('param' === $type) {
if ('' !== $value) {
$parameters[$name] = $value;
}
} elseif ('default' === $type) {
$defaults[$name] = $value;
} elseif ('route' === $type) {
$route = $value;
} elseif ('allow' === $type) {
$allow[] = $name;
}
unset($_SERVER[$key]);
}
if (null !== $route) {
$parameters['_route'] = $route;
return $this->mergeDefaults($parameters, $defaults);
} elseif (0 < count($allow)) {
throw new MethodNotAllowedException($allow);
} else {
return parent::match($pathinfo);
}
}
/**
* Denormalizes an array of values.
*
* @param string[] $values
*
* @return array
*/
private function denormalizeValues(array $values)
{
$normalizedValues = array();
foreach ($values as $key => $value) {
if (preg_match('~^(.*)\[(\d+)\]$~', $key, $matches)) {
if (!isset($normalizedValues[$matches[1]])) {
$normalizedValues[$matches[1]] = array();
}
$normalizedValues[$matches[1]][(int) $matches[2]] = $value;
} else {
$normalizedValues[$key] = $value;
}
}
return $normalizedValues;
}
}

View File

@@ -1,281 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Routing\Matcher\Dumper;
use Symfony\Component\Routing\Route;
/**
* Dumps a set of Apache mod_rewrite rules.
*
* @deprecated Deprecated since version 2.5, to be removed in 3.0.
* The performance gains are minimal and it's very hard to replicate
* the behavior of PHP implementation.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Kris Wallsmith <kris@symfony.com>
*/
class ApacheMatcherDumper extends MatcherDumper
{
/**
* Dumps a set of Apache mod_rewrite rules.
*
* Available options:
*
* * script_name: The script name (app.php by default)
* * base_uri: The base URI ("" by default)
*
* @param array $options An array of options
*
* @return string A string to be used as Apache rewrite rules
*
* @throws \LogicException When the route regex is invalid
*/
public function dump(array $options = array())
{
$options = array_merge(array(
'script_name' => 'app.php',
'base_uri' => '',
), $options);
$options['script_name'] = self::escape($options['script_name'], ' ', '\\');
$rules = array("# skip \"real\" requests\nRewriteCond %{REQUEST_FILENAME} -f\nRewriteRule .* - [QSA,L]");
$methodVars = array();
$hostRegexUnique = 0;
$prevHostRegex = '';
foreach ($this->getRoutes()->all() as $name => $route) {
if ($route->getCondition()) {
throw new \LogicException(sprintf('Unable to dump the routes for Apache as route "%s" has a condition.', $name));
}
$compiledRoute = $route->compile();
$hostRegex = $compiledRoute->getHostRegex();
if (null !== $hostRegex && $prevHostRegex !== $hostRegex) {
$prevHostRegex = $hostRegex;
++$hostRegexUnique;
$rule = array();
$regex = $this->regexToApacheRegex($hostRegex);
$regex = self::escape($regex, ' ', '\\');
$rule[] = sprintf('RewriteCond %%{HTTP:Host} %s', $regex);
$variables = array();
$variables[] = sprintf('E=__ROUTING_host_%s:1', $hostRegexUnique);
foreach ($compiledRoute->getHostVariables() as $i => $variable) {
$variables[] = sprintf('E=__ROUTING_host_%s_%s:%%%d', $hostRegexUnique, $variable, $i + 1);
}
$variables = implode(',', $variables);
$rule[] = sprintf('RewriteRule .? - [%s]', $variables);
$rules[] = implode("\n", $rule);
}
$rules[] = $this->dumpRoute($name, $route, $options, $hostRegexUnique);
if ($req = $route->getRequirement('_method')) {
$methods = explode('|', strtoupper($req));
$methodVars = array_merge($methodVars, $methods);
}
}
if (0 < count($methodVars)) {
$rule = array('# 405 Method Not Allowed');
$methodVars = array_values(array_unique($methodVars));
if (in_array('GET', $methodVars) && !in_array('HEAD', $methodVars)) {
$methodVars[] = 'HEAD';
}
foreach ($methodVars as $i => $methodVar) {
$rule[] = sprintf('RewriteCond %%{ENV:_ROUTING__allow_%s} =1%s', $methodVar, isset($methodVars[$i + 1]) ? ' [OR]' : '');
}
$rule[] = sprintf('RewriteRule .* %s [QSA,L]', $options['script_name']);
$rules[] = implode("\n", $rule);
}
return implode("\n\n", $rules)."\n";
}
/**
* Dumps a single route.
*
* @param string $name Route name
* @param Route $route The route
* @param array $options Options
* @param bool $hostRegexUnique Unique identifier for the host regex
*
* @return string The compiled route
*/
private function dumpRoute($name, $route, array $options, $hostRegexUnique)
{
$compiledRoute = $route->compile();
// prepare the apache regex
$regex = $this->regexToApacheRegex($compiledRoute->getRegex());
$regex = '^'.self::escape(preg_quote($options['base_uri']).substr($regex, 1), ' ', '\\');
$methods = $this->getRouteMethods($route);
$hasTrailingSlash = (!$methods || in_array('HEAD', $methods)) && '/$' === substr($regex, -2) && '^/$' !== $regex;
$variables = array('E=_ROUTING_route:'.$name);
foreach ($compiledRoute->getHostVariables() as $variable) {
$variables[] = sprintf('E=_ROUTING_param_%s:%%{ENV:__ROUTING_host_%s_%s}', $variable, $hostRegexUnique, $variable);
}
foreach ($compiledRoute->getPathVariables() as $i => $variable) {
$variables[] = 'E=_ROUTING_param_'.$variable.':%'.($i + 1);
}
foreach ($this->normalizeValues($route->getDefaults()) as $key => $value) {
$variables[] = 'E=_ROUTING_default_'.$key.':'.strtr($value, array(
':' => '\\:',
'=' => '\\=',
'\\' => '\\\\',
' ' => '\\ ',
));
}
$variables = implode(',', $variables);
$rule = array("# $name");
// method mismatch
if (0 < count($methods)) {
$allow = array();
foreach ($methods as $method) {
$allow[] = 'E=_ROUTING_allow_'.$method.':1';
}
if ($compiledRoute->getHostRegex()) {
$rule[] = sprintf('RewriteCond %%{ENV:__ROUTING_host_%s} =1', $hostRegexUnique);
}
$rule[] = "RewriteCond %{REQUEST_URI} $regex";
$rule[] = sprintf('RewriteCond %%{REQUEST_METHOD} !^(%s)$ [NC]', implode('|', $methods));
$rule[] = sprintf('RewriteRule .* - [S=%d,%s]', $hasTrailingSlash ? 2 : 1, implode(',', $allow));
}
// redirect with trailing slash appended
if ($hasTrailingSlash) {
if ($compiledRoute->getHostRegex()) {
$rule[] = sprintf('RewriteCond %%{ENV:__ROUTING_host_%s} =1', $hostRegexUnique);
}
$rule[] = 'RewriteCond %{REQUEST_URI} '.substr($regex, 0, -2).'$';
$rule[] = 'RewriteRule .* $0/ [QSA,L,R=301]';
}
// the main rule
if ($compiledRoute->getHostRegex()) {
$rule[] = sprintf('RewriteCond %%{ENV:__ROUTING_host_%s} =1', $hostRegexUnique);
}
$rule[] = "RewriteCond %{REQUEST_URI} $regex";
$rule[] = "RewriteRule .* {$options['script_name']} [QSA,L,$variables]";
return implode("\n", $rule);
}
/**
* Returns methods allowed for a route.
*
* @param Route $route The route
*
* @return array The methods
*/
private function getRouteMethods(Route $route)
{
$methods = array();
if ($req = $route->getRequirement('_method')) {
$methods = explode('|', strtoupper($req));
// GET and HEAD are equivalent
if (in_array('GET', $methods) && !in_array('HEAD', $methods)) {
$methods[] = 'HEAD';
}
}
return $methods;
}
/**
* Converts a regex to make it suitable for mod_rewrite.
*
* @param string $regex The regex
*
* @return string The converted regex
*/
private function regexToApacheRegex($regex)
{
$regexPatternEnd = strrpos($regex, $regex[0]);
return preg_replace('/\?P<.+?>/', '', substr($regex, 1, $regexPatternEnd - 1));
}
/**
* Escapes a string.
*
* @param string $string The string to be escaped
* @param string $char The character to be escaped
* @param string $with The character to be used for escaping
*
* @return string The escaped string
*/
private static function escape($string, $char, $with)
{
$escaped = false;
$output = '';
foreach (str_split($string) as $symbol) {
if ($escaped) {
$output .= $symbol;
$escaped = false;
continue;
}
if ($symbol === $char) {
$output .= $with.$char;
continue;
}
if ($symbol === $with) {
$escaped = true;
}
$output .= $symbol;
}
return $output;
}
/**
* Normalizes an array of values.
*
* @param array $values
*
* @return string[]
*/
private function normalizeValues(array $values)
{
$normalizedValues = array();
foreach ($values as $key => $value) {
if (is_array($value)) {
foreach ($value as $index => $bit) {
$normalizedValues[sprintf('%s[%s]', $key, $index)] = $bit;
}
} else {
$normalizedValues[$key] = (string) $value;
}
}
return $normalizedValues;
}
}

View File

@@ -1,36 +0,0 @@
Routing Component
=================
Routing associates a request with the code that will convert it to a response.
The example below demonstrates how you can set up a fully working routing
system:
```php
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
$routes = new RouteCollection();
$routes->add('hello', new Route('/hello', array('controller' => 'foo')));
$context = new RequestContext();
// this is optional and can be done without a Request instance
$context->fromRequest(Request::createFromGlobals());
$matcher = new UrlMatcher($routes, $context);
$parameters = $matcher->match('/hello');
```
Resources
---------
You can run the unit tests with the following command:
$ cd path/to/Symfony/Component/Routing/
$ composer install
$ phpunit

View File

@@ -1,204 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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 Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Matcher\Dumper\ApacheMatcherDumper;
/**
* @group legacy
*/
class LegacyApacheMatcherDumperTest extends \PHPUnit_Framework_TestCase
{
protected static $fixturesPath;
public static function setUpBeforeClass()
{
self::$fixturesPath = realpath(__DIR__.'/../../Fixtures/');
}
protected function setUp()
{
$this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED);
}
public function testDump()
{
$dumper = new ApacheMatcherDumper($this->getRouteCollection());
$this->assertStringEqualsFile(self::$fixturesPath.'/dumper/url_matcher1.apache', $dumper->dump(), '->dump() dumps basic routes to the correct apache format.');
}
/**
* @dataProvider provideEscapeFixtures
*/
public function testEscapePattern($src, $dest, $char, $with, $message)
{
$r = new \ReflectionMethod(new ApacheMatcherDumper($this->getRouteCollection()), 'escape');
$r->setAccessible(true);
$this->assertEquals($dest, $r->invoke(null, $src, $char, $with), $message);
}
public function provideEscapeFixtures()
{
return array(
array('foo', 'foo', ' ', '-', 'Preserve string that should not be escaped'),
array('fo-o', 'fo-o', ' ', '-', 'Preserve string that should not be escaped'),
array('fo o', 'fo- o', ' ', '-', 'Escape special characters'),
array('fo-- o', 'fo--- o', ' ', '-', 'Escape special characters'),
array('fo- o', 'fo- o', ' ', '-', 'Do not escape already escaped string'),
);
}
public function testEscapeScriptName()
{
$collection = new RouteCollection();
$collection->add('foo', new Route('/foo'));
$dumper = new ApacheMatcherDumper($collection);
$this->assertStringEqualsFile(self::$fixturesPath.'/dumper/url_matcher2.apache', $dumper->dump(array('script_name' => 'ap p_d\ ev.php')));
}
private function getRouteCollection()
{
$collection = new RouteCollection();
// defaults and requirements
$collection->add('foo', new Route(
'/foo/{bar}',
array('def' => 'test'),
array('bar' => 'baz|symfony')
));
// defaults parameters in pattern
$collection->add('foobar', new Route(
'/foo/{bar}',
array('bar' => 'toto')
));
// method requirement
$collection->add('bar', new Route(
'/bar/{foo}',
array(),
array('_method' => 'GET|head')
));
// method requirement (again)
$collection->add('baragain', new Route(
'/baragain/{foo}',
array(),
array('_method' => 'get|post')
));
// 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 safe method
$collection->add('baz5', new Route(
'/test/{foo}/',
array(),
array('_method' => 'get')
));
// trailing slash and unsafe method
$collection->add('baz5unsafe', new Route(
'/testunsafe/{foo}/',
array(),
array('_method' => 'post')
));
// complex
$collection->add('baz6', new Route(
'/test/baz',
array('foo' => 'bar baz')
));
// space in path
$collection->add('baz7', new Route(
'/te st/baz'
));
// space preceded with \ in path
$collection->add('baz8', new Route(
'/te\\ st/baz'
));
// space preceded with \ in requirement
$collection->add('baz9', new Route(
'/test/{baz}',
array(),
array(
'baz' => 'te\\\\ st',
)
));
$collection1 = new RouteCollection();
$route1 = new Route('/route1', array(), array(), array(), 'a.example.com');
$collection1->add('route1', $route1);
$collection2 = new RouteCollection();
$route2 = new Route('/route2', array(), array(), array(), 'a.example.com');
$collection2->add('route2', $route2);
$route3 = new Route('/route3', array(), array(), array(), 'b.example.com');
$collection2->add('route3', $route3);
$collection2->addPrefix('/c2');
$collection1->addCollection($collection2);
$route4 = new Route('/route4', array(), array(), array(), 'a.example.com');
$collection1->add('route4', $route4);
$route5 = new Route('/route5', array(), array(), array(), 'c.example.com');
$collection1->add('route5', $route5);
$route6 = new Route('/route6', array(), array(), array(), null);
$collection1->add('route6', $route6);
$collection->addCollection($collection1);
// host and variables
$collection1 = new RouteCollection();
$route11 = new Route('/route11', array(), array(), array(), '{var1}.example.com');
$collection1->add('route11', $route11);
$route12 = new Route('/route12', array('var1' => 'val'), array(), array(), '{var1}.example.com');
$collection1->add('route12', $route12);
$route13 = new Route('/route13/{name}', array(), array(), array(), '{var1}.example.com');
$collection1->add('route13', $route13);
$route14 = new Route('/route14/{name}', array('var1' => 'val'), array(), array(), '{var1}.example.com');
$collection1->add('route14', $route14);
$route15 = new Route('/route15/{name}', array(), array(), array(), 'c.example.com');
$collection1->add('route15', $route15);
$route16 = new Route('/route16/{name}', array('var1' => 'val'), array(), array(), null);
$collection1->add('route16', $route16);
$route17 = new Route('/route17', array(), array(), array(), null);
$collection1->add('route17', $route17);
$collection->addCollection($collection1);
return $collection;
}
}

View File

@@ -1,156 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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\RouteCollection;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Matcher\ApacheUrlMatcher;
/**
* @group legacy
*/
class LegacyApacheUrlMatcherTest extends \PHPUnit_Framework_TestCase
{
protected $server;
protected function setUp()
{
$this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED);
$this->server = $_SERVER;
}
protected function tearDown()
{
$_SERVER = $this->server;
}
/**
* @dataProvider getMatchData
*/
public function testMatch($name, $pathinfo, $server, $expect)
{
$collection = new RouteCollection();
$context = new RequestContext();
$matcher = new ApacheUrlMatcher($collection, $context);
$_SERVER = $server;
$result = $matcher->match($pathinfo);
$this->assertSame(var_export($expect, true), var_export($result, true));
}
public function getMatchData()
{
return array(
array(
'Simple route',
'/hello/world',
array(
'_ROUTING_route' => 'hello',
'_ROUTING_param__controller' => 'AcmeBundle:Default:index',
'_ROUTING_param_name' => 'world',
),
array(
'_controller' => 'AcmeBundle:Default:index',
'name' => 'world',
'_route' => 'hello',
),
),
array(
'Route with params and defaults',
'/hello/hugo',
array(
'_ROUTING_route' => 'hello',
'_ROUTING_param__controller' => 'AcmeBundle:Default:index',
'_ROUTING_param_name' => 'hugo',
'_ROUTING_default_name' => 'world',
),
array(
'name' => 'hugo',
'_controller' => 'AcmeBundle:Default:index',
'_route' => 'hello',
),
),
array(
'Route with defaults only',
'/hello',
array(
'_ROUTING_route' => 'hello',
'_ROUTING_param__controller' => 'AcmeBundle:Default:index',
'_ROUTING_default_name' => 'world',
),
array(
'name' => 'world',
'_controller' => 'AcmeBundle:Default:index',
'_route' => 'hello',
),
),
array(
'Redirect with many ignored attributes',
'/legacy/{cat1}/{cat2}/{id}.html',
array(
'_ROUTING_route' => 'product_view',
'_ROUTING_param__controller' => 'FrameworkBundle:Redirect:redirect',
'_ROUTING_default_ignoreAttributes[0]' => 'attr_a',
'_ROUTING_default_ignoreAttributes[1]' => 'attr_b',
),
array(
'ignoreAttributes' => array('attr_a', 'attr_b'),
'_controller' => 'FrameworkBundle:Redirect:redirect',
'_route' => 'product_view',
),
),
array(
'REDIRECT_ envs',
'/hello/world',
array(
'REDIRECT__ROUTING_route' => 'hello',
'REDIRECT__ROUTING_param__controller' => 'AcmeBundle:Default:index',
'REDIRECT__ROUTING_param_name' => 'world',
),
array(
'_controller' => 'AcmeBundle:Default:index',
'name' => 'world',
'_route' => 'hello',
),
),
array(
'REDIRECT_REDIRECT_ envs',
'/hello/world',
array(
'REDIRECT_REDIRECT__ROUTING_route' => 'hello',
'REDIRECT_REDIRECT__ROUTING_param__controller' => 'AcmeBundle:Default:index',
'REDIRECT_REDIRECT__ROUTING_param_name' => 'world',
),
array(
'_controller' => 'AcmeBundle:Default:index',
'name' => 'world',
'_route' => 'hello',
),
),
array(
'REDIRECT_REDIRECT_ envs',
'/hello/world',
array(
'REDIRECT_REDIRECT__ROUTING_route' => 'hello',
'REDIRECT_REDIRECT__ROUTING_param__controller' => 'AcmeBundle:Default:index',
'REDIRECT_REDIRECT__ROUTING_param_name' => 'world',
),
array(
'_controller' => 'AcmeBundle:Default:index',
'name' => 'world',
'_route' => 'hello',
),
),
);
}
}

View File

@@ -36,25 +36,14 @@ class RouteTest extends \PHPUnit_Framework_TestCase
{
return array(
array('value', '/Blog', 'getPath'),
array('requirements', array('_method' => 'GET'), 'getRequirements'),
array('requirements', array('locale' => 'en'), 'getRequirements'),
array('options', array('compiler_class' => 'RouteCompiler'), 'getOptions'),
array('name', 'blog_index', 'getName'),
array('defaults', array('_controller' => 'MyBlogBundle:Blog:index'), 'getDefaults'),
array('schemes', array('https'), 'getSchemes'),
array('methods', array('GET', 'POST'), 'getMethods'),
array('host', array('{locale}.example.com'), 'getHost'),
array('condition', array('context.getMethod() == "GET"'), 'getCondition'),
array('host', '{locale}.example.com', 'getHost'),
array('condition', 'context.getMethod() == "GET"', 'getCondition'),
);
}
/**
* @group legacy
*/
public function testLegacyGetPattern()
{
$this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED);
$route = new Route(array('value' => '/Blog'));
$this->assertEquals($route->getPattern(), '/Blog');
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses;
trait FooTrait
{
public function doBar()
{
$baz = self::class;
if (true) {
}
}
}

View File

@@ -0,0 +1,19 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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)
{
}
}

View File

@@ -0,0 +1,3 @@
blog_show:
path: /blog/{slug}
defaults: { _controller: "MyBundle:Blog:show" }

View File

@@ -0,0 +1,2 @@
route1:
path: /route/1

View File

@@ -0,0 +1,2 @@
route2:
path: /route/2

View File

@@ -0,0 +1,2 @@
route3:
path: /route/3

View File

@@ -0,0 +1,3 @@
_directory:
resource: "../directory"
type: directory

View File

View File

View File

@@ -6,6 +6,5 @@
<route id="blog_show" path="/blog/{slug}">
<default key="_controller">MyBundle:Blog:show</default>
<requirement key="_method">GET</requirement>
<!-- </route> -->
</routes>

View File

@@ -6,7 +6,6 @@
<route id="blog_show" path="/blog/{slug}">
<default key="_controller">MyBundle:Blog:show</default>
<requirement key="_method">GET</requirement>
<option key="compiler_class">RouteCompiler</option>
<foo key="bar">baz</foo>
</route>

View File

@@ -14,15 +14,5 @@ $collection->add('blog_show', new Route(
array('GET', 'POST', 'put', 'OpTiOnS'),
'context.getMethod() == "GET"'
));
$collection->add('blog_show_legacy', new Route(
'/blog/{slug}',
array('_controller' => 'MyBlogBundle:Blog:show'),
array('_method' => 'GET|POST|put|OpTiOnS', '_scheme' => 'https', 'locale' => '\w+'),
array('compiler_class' => 'RouteCompiler'),
'{locale}.example.com',
array(),
array(),
'context.getMethod() == "GET"'
));
return $collection;

View File

@@ -11,15 +11,5 @@
<condition>context.getMethod() == "GET"</condition>
</route>
<route id="blog_show_legacy" pattern="/blog/{slug}" host="{locale}.example.com">
<default key="_controller">MyBundle:Blog:show</default>
<default key="slug" xsi:nil="true" />
<requirement key="_method">GET|POST|put|OpTiOnS</requirement>
<requirement key="_scheme">hTTps</requirement>
<requirement key="locale">\w+</requirement>
<option key="compiler_class">RouteCompiler</option>
<condition>context.getMethod() == "GET"</condition>
</route>
<route id="blog_show_inherited" path="/blog/{slug}" />
</routes>

View File

@@ -9,14 +9,5 @@ blog_show:
options:
compiler_class: RouteCompiler
blog_show_legacy:
pattern: /blog/{slug}
defaults: { _controller: "MyBundle:Blog:show" }
host: "{locale}.example.com"
requirements: { '_method': 'GET|POST|put|OpTiOnS', _scheme: https, 'locale': '\w+' }
condition: 'context.getMethod() == "GET"'
options:
compiler_class: RouteCompiler
blog_show_inherited:
path: /blog/{slug}

Some files were not shown because too many files have changed in this diff Show More