]> source.dussan.org Git - nextcloud-server.git/commitdiff
Include copy of Symfony routing component, and don't use composer
authorBart Visscher <bartv@thisnet.nl>
Sat, 27 Oct 2012 14:24:24 +0000 (16:24 +0200)
committerBart Visscher <bartv@thisnet.nl>
Sat, 27 Oct 2012 14:24:24 +0000 (16:24 +0200)
44 files changed:
.gitignore
3rdparty/bin/composer [deleted file]
3rdparty/symfony/routing/Symfony/Component/Routing/Annotation/Route.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/CompiledRoute.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Exception/ExceptionInterface.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Exception/InvalidParameterException.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Exception/MethodNotAllowedException.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Exception/MissingMandatoryParametersException.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Exception/ResourceNotFoundException.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Exception/RouteNotFoundException.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumper.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumperInterface.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Generator/UrlGenerator.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/LICENSE [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Loader/AnnotationClassLoader.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Loader/AnnotationFileLoader.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Loader/ClosureLoader.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Loader/PhpFileLoader.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Loader/XmlFileLoader.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Loader/YamlFileLoader.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/ApacheUrlMatcher.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumper.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumperInterface.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcher.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcherInterface.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcher.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcherInterface.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/README.md [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/RequestContext.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/RequestContextAwareInterface.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Route.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/RouteCollection.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/RouteCompiler.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/RouteCompilerInterface.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/Router.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/RouterInterface.php [new file with mode: 0644]
3rdparty/symfony/routing/Symfony/Component/Routing/composer.json [new file with mode: 0644]
composer.json [deleted file]

index 4ae39ed7facd0f80283568f8a39ad1b817cf0abd..4749dea19dc782532161ee51266e5a02e9b19602 100644 (file)
@@ -54,7 +54,3 @@ nbproject
 # WebFinger
 .well-known
 /.buildpath
-3rdparty/autoload.php
-3rdparty/composer/
-3rdparty/symfony/
-composer.lock
diff --git a/3rdparty/bin/composer b/3rdparty/bin/composer
deleted file mode 100755 (executable)
index 7999bd4..0000000
Binary files a/3rdparty/bin/composer and /dev/null differ
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Annotation/Route.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Annotation/Route.php
new file mode 100644 (file)
index 0000000..f60af46
--- /dev/null
@@ -0,0 +1,103 @@
+<?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\Annotation;
+
+/**
+ * Annotation class for @Route().
+ *
+ * @Annotation
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class Route
+{
+    private $pattern;
+    private $name;
+    private $requirements;
+    private $options;
+    private $defaults;
+
+    /**
+     * Constructor.
+     *
+     * @param array $data An array of key/value parameters.
+     */
+    public function __construct(array $data)
+    {
+        $this->requirements = array();
+        $this->options = array();
+        $this->defaults = array();
+
+        if (isset($data['value'])) {
+            $data['pattern'] = $data['value'];
+            unset($data['value']);
+        }
+
+        foreach ($data as $key => $value) {
+            $method = 'set'.$key;
+            if (!method_exists($this, $method)) {
+                throw new \BadMethodCallException(sprintf("Unknown property '%s' on annotation '%s'.", $key, get_class($this)));
+            }
+            $this->$method($value);
+        }
+    }
+
+    public function setPattern($pattern)
+    {
+        $this->pattern = $pattern;
+    }
+
+    public function getPattern()
+    {
+        return $this->pattern;
+    }
+
+    public function setName($name)
+    {
+        $this->name = $name;
+    }
+
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    public function setRequirements($requirements)
+    {
+        $this->requirements = $requirements;
+    }
+
+    public function getRequirements()
+    {
+        return $this->requirements;
+    }
+
+    public function setOptions($options)
+    {
+        $this->options = $options;
+    }
+
+    public function getOptions()
+    {
+        return $this->options;
+    }
+
+    public function setDefaults($defaults)
+    {
+        $this->defaults = $defaults;
+    }
+
+    public function getDefaults()
+    {
+        return $this->defaults;
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/CompiledRoute.php b/3rdparty/symfony/routing/Symfony/Component/Routing/CompiledRoute.php
new file mode 100644 (file)
index 0000000..c86c9ec
--- /dev/null
@@ -0,0 +1,134 @@
+<?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;
+
+/**
+ * CompiledRoutes are returned by the RouteCompiler class.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class CompiledRoute
+{
+    private $route;
+    private $variables;
+    private $tokens;
+    private $staticPrefix;
+    private $regex;
+
+    /**
+     * Constructor.
+     *
+     * @param Route  $route        A original Route instance
+     * @param string $staticPrefix The static prefix of the compiled route
+     * @param string $regex        The regular expression to use to match this route
+     * @param array  $tokens       An array of tokens to use to generate URL for this route
+     * @param array  $variables    An array of variables
+     */
+    public function __construct(Route $route, $staticPrefix, $regex, array $tokens, array $variables)
+    {
+        $this->route = $route;
+        $this->staticPrefix = $staticPrefix;
+        $this->regex = $regex;
+        $this->tokens = $tokens;
+        $this->variables = $variables;
+    }
+
+    /**
+     * Returns the Route instance.
+     *
+     * @return Route A Route instance
+     */
+    public function getRoute()
+    {
+        return $this->route;
+    }
+
+    /**
+     * Returns the static prefix.
+     *
+     * @return string The static prefix
+     */
+    public function getStaticPrefix()
+    {
+        return $this->staticPrefix;
+    }
+
+    /**
+     * Returns the regex.
+     *
+     * @return string The regex
+     */
+    public function getRegex()
+    {
+        return $this->regex;
+    }
+
+    /**
+     * Returns the tokens.
+     *
+     * @return array The tokens
+     */
+    public function getTokens()
+    {
+        return $this->tokens;
+    }
+
+    /**
+     * Returns the variables.
+     *
+     * @return array The variables
+     */
+    public function getVariables()
+    {
+        return $this->variables;
+    }
+
+    /**
+     * Returns the pattern.
+     *
+     * @return string The pattern
+     */
+    public function getPattern()
+    {
+        return $this->route->getPattern();
+    }
+
+    /**
+     * Returns the options.
+     *
+     * @return array The options
+     */
+    public function getOptions()
+    {
+        return $this->route->getOptions();
+    }
+
+    /**
+     * Returns the defaults.
+     *
+     * @return array The defaults
+     */
+    public function getDefaults()
+    {
+        return $this->route->getDefaults();
+    }
+
+    /**
+     * Returns the requirements.
+     *
+     * @return array The requirements
+     */
+    public function getRequirements()
+    {
+        return $this->route->getRequirements();
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Exception/ExceptionInterface.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Exception/ExceptionInterface.php
new file mode 100644 (file)
index 0000000..5289f52
--- /dev/null
@@ -0,0 +1,23 @@
+<?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\Exception;
+
+/**
+ * ExceptionInterface
+ *
+ * @author Alexandre Salomé <alexandre.salome@gmail.com>
+ *
+ * @api
+ */
+interface ExceptionInterface
+{
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Exception/InvalidParameterException.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Exception/InvalidParameterException.php
new file mode 100644 (file)
index 0000000..4f12469
--- /dev/null
@@ -0,0 +1,23 @@
+<?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\Exception;
+
+/**
+ * Exception thrown when a parameter is not valid
+ *
+ * @author Alexandre Salomé <alexandre.salome@gmail.com>
+ *
+ * @api
+ */
+class InvalidParameterException extends \InvalidArgumentException implements ExceptionInterface
+{
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Exception/MethodNotAllowedException.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Exception/MethodNotAllowedException.php
new file mode 100644 (file)
index 0000000..470ce52
--- /dev/null
@@ -0,0 +1,38 @@
+<?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\Exception;
+
+/**
+ * The resource was found but the request method is not allowed.
+ *
+ * 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
+{
+    protected $allowedMethods;
+
+    public function __construct(array $allowedMethods, $message = null, $code = 0, \Exception $previous = null)
+    {
+        $this->allowedMethods = array_map('strtoupper', $allowedMethods);
+
+        parent::__construct($message, $code, $previous);
+    }
+
+    public function getAllowedMethods()
+    {
+        return $this->allowedMethods;
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Exception/MissingMandatoryParametersException.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Exception/MissingMandatoryParametersException.php
new file mode 100644 (file)
index 0000000..5a523fa
--- /dev/null
@@ -0,0 +1,24 @@
+<?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\Exception;
+
+/**
+ * Exception thrown when a route cannot be generated because of missing
+ * mandatory parameters.
+ *
+ * @author Alexandre Salomé <alexandre.salome@gmail.com>
+ *
+ * @api
+ */
+class MissingMandatoryParametersException extends \InvalidArgumentException implements ExceptionInterface
+{
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Exception/ResourceNotFoundException.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Exception/ResourceNotFoundException.php
new file mode 100644 (file)
index 0000000..362a0d6
--- /dev/null
@@ -0,0 +1,25 @@
+<?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\Exception;
+
+/**
+ * The resource was not found.
+ *
+ * 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
+{
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Exception/RouteNotFoundException.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Exception/RouteNotFoundException.php
new file mode 100644 (file)
index 0000000..4d5f288
--- /dev/null
@@ -0,0 +1,23 @@
+<?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\Exception;
+
+/**
+ * Exception thrown when a route does not exists
+ *
+ * @author Alexandre Salomé <alexandre.salome@gmail.com>
+ *
+ * @api
+ */
+class RouteNotFoundException extends \InvalidArgumentException implements ExceptionInterface
+{
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumper.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumper.php
new file mode 100644 (file)
index 0000000..1291bd1
--- /dev/null
@@ -0,0 +1,39 @@
+<?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\Generator\Dumper;
+
+use Symfony\Component\Routing\RouteCollection;
+
+/**
+ * GeneratorDumper is the base class for all built-in generator dumpers.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+abstract class GeneratorDumper implements GeneratorDumperInterface
+{
+    private $routes;
+
+    /**
+     * Constructor.
+     *
+     * @param RouteCollection $routes The RouteCollection to dump
+     */
+    public function __construct(RouteCollection $routes)
+    {
+        $this->routes = $routes;
+    }
+
+    public function getRoutes()
+    {
+        return $this->routes;
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumperInterface.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumperInterface.php
new file mode 100644 (file)
index 0000000..6f5353c
--- /dev/null
@@ -0,0 +1,45 @@
+<?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\Generator\Dumper;
+
+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
+{
+    /**
+     * Dumps a set of routes to a PHP class.
+     *
+     * Available options:
+     *
+     *  * class:      The class name
+     *  * base_class: The base class name
+     *
+     * @param array $options An array of options
+     *
+     * @return string A PHP class representing the generator class
+     */
+    public function dump(array $options = array());
+
+    /**
+     * Gets the routes to dump.
+     *
+     * @return RouteCollection A RouteCollection instance
+     */
+    public function getRoutes();
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php
new file mode 100644 (file)
index 0000000..080dd3a
--- /dev/null
@@ -0,0 +1,150 @@
+<?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\Generator\Dumper;
+
+use Symfony\Component\Routing\Route;
+
+/**
+ * PhpGeneratorDumper creates a PHP class able to generate URLs for a given set of routes.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @api
+ */
+class PhpGeneratorDumper extends GeneratorDumper
+{
+    /**
+     * Dumps a set of routes to a PHP class.
+     *
+     * Available options:
+     *
+     *  * class:      The class name
+     *  * base_class: The base class name
+     *
+     * @param array $options An array of options
+     *
+     * @return string A PHP class representing the generator class
+     *
+     * @api
+     */
+    public function dump(array $options = array())
+    {
+        $options = array_merge(array(
+            'class'      => 'ProjectUrlGenerator',
+            'base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
+        ), $options);
+
+        return
+            $this->startClass($options['class'], $options['base_class']).
+            $this->addConstructor().
+            $this->addGenerator().
+            $this->endClass()
+        ;
+    }
+
+    private function addGenerator()
+    {
+        $methods = array();
+        foreach ($this->getRoutes()->all() as $name => $route) {
+            $compiledRoute = $route->compile();
+
+            $variables = str_replace("\n", '', var_export($compiledRoute->getVariables(), true));
+            $defaults = str_replace("\n", '', var_export($compiledRoute->getDefaults(), true));
+            $requirements = str_replace("\n", '', var_export($compiledRoute->getRequirements(), true));
+            $tokens = str_replace("\n", '', var_export($compiledRoute->getTokens(), true));
+
+            $escapedName = str_replace('.', '__', $name);
+
+            $methods[] = <<<EOF
+    private function get{$escapedName}RouteInfo()
+    {
+        return array($variables, $defaults, $requirements, $tokens);
+    }
+
+EOF
+            ;
+        }
+
+        $methods = implode("\n", $methods);
+
+        return <<<EOF
+
+    public function generate(\$name, \$parameters = array(), \$absolute = false)
+    {
+        if (!isset(self::\$declaredRouteNames[\$name])) {
+            throw new RouteNotFoundException(sprintf('Route "%s" does not exist.', \$name));
+        }
+
+        \$escapedName = str_replace('.', '__', \$name);
+
+        list(\$variables, \$defaults, \$requirements, \$tokens) = \$this->{'get'.\$escapedName.'RouteInfo'}();
+
+        return \$this->doGenerate(\$variables, \$defaults, \$requirements, \$tokens, \$parameters, \$name, \$absolute);
+    }
+
+$methods
+EOF;
+    }
+
+    private function startClass($class, $baseClass)
+    {
+        $routes = array();
+        foreach ($this->getRoutes()->all() as $name => $route) {
+            $routes[] = "       '$name' => true,";
+        }
+        $routes  = implode("\n", $routes);
+
+        return <<<EOF
+<?php
+
+use Symfony\Component\Routing\RequestContext;
+use Symfony\Component\Routing\Exception\RouteNotFoundException;
+
+
+/**
+ * $class
+ *
+ * This class has been auto-generated
+ * by the Symfony Routing Component.
+ */
+class $class extends $baseClass
+{
+    static private \$declaredRouteNames = array(
+$routes
+    );
+
+
+EOF;
+    }
+
+    private function addConstructor()
+    {
+        return <<<EOF
+    /**
+     * Constructor.
+     */
+    public function __construct(RequestContext \$context)
+    {
+        \$this->context = \$context;
+    }
+
+EOF;
+    }
+
+    private function endClass()
+    {
+        return <<<EOF
+}
+
+EOF;
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Generator/UrlGenerator.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Generator/UrlGenerator.php
new file mode 100644 (file)
index 0000000..28aca47
--- /dev/null
@@ -0,0 +1,176 @@
+<?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\Generator;
+
+use Symfony\Component\Routing\Route;
+use Symfony\Component\Routing\RouteCollection;
+use Symfony\Component\Routing\RequestContext;
+use Symfony\Component\Routing\Exception\InvalidParameterException;
+use Symfony\Component\Routing\Exception\RouteNotFoundException;
+use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
+
+/**
+ * UrlGenerator generates URL based on a set of routes.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @api
+ */
+class UrlGenerator implements UrlGeneratorInterface
+{
+    protected $context;
+    protected $decodedChars = array(
+        // %2F is not valid in a URL, so we don't encode it (which is fine as the requirements explicitly allowed it)
+        '%2F' => '/',
+    );
+
+    protected $routes;
+    protected $cache;
+
+    /**
+     * Constructor.
+     *
+     * @param RouteCollection $routes  A RouteCollection instance
+     * @param RequestContext  $context The context
+     *
+     * @api
+     */
+    public function __construct(RouteCollection $routes, RequestContext $context)
+    {
+        $this->routes = $routes;
+        $this->context = $context;
+        $this->cache = array();
+    }
+
+    /**
+     * Sets the request context.
+     *
+     * @param RequestContext $context The context
+     *
+     * @api
+     */
+    public function setContext(RequestContext $context)
+    {
+        $this->context = $context;
+    }
+
+    /**
+     * Gets the request context.
+     *
+     * @return RequestContext The context
+     */
+    public function getContext()
+    {
+        return $this->context;
+    }
+
+    /**
+     * Generates a URL from the given parameters.
+     *
+     * @param string  $name       The name of the route
+     * @param mixed   $parameters An array of parameters
+     * @param Boolean $absolute   Whether to generate an absolute URL
+     *
+     * @return string The generated URL
+     *
+     * @throws Symfony\Component\Routing\Exception\RouteNotFoundException When route doesn't exist
+     *
+     * @api
+     */
+    public function generate($name, $parameters = array(), $absolute = false)
+    {
+        if (null === $route = $this->routes->get($name)) {
+            throw new RouteNotFoundException(sprintf('Route "%s" does not exist.', $name));
+        }
+
+        if (!isset($this->cache[$name])) {
+            $this->cache[$name] = $route->compile();
+        }
+
+        return $this->doGenerate($this->cache[$name]->getVariables(), $route->getDefaults(), $route->getRequirements(), $this->cache[$name]->getTokens(), $parameters, $name, $absolute);
+    }
+
+    /**
+     * @throws Symfony\Component\Routing\Exception\MissingMandatoryParametersException When route has some missing mandatory parameters
+     * @throws Symfony\Component\Routing\Exception\InvalidParameterException When a parameter value is not correct
+     */
+    protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $absolute)
+    {
+        $variables = array_flip($variables);
+
+        $originParameters = $parameters;
+        $parameters = array_replace($this->context->getParameters(), $parameters);
+        $tparams = array_replace($defaults, $parameters);
+
+        // all params must be given
+        if ($diff = array_diff_key($variables, $tparams)) {
+            throw new MissingMandatoryParametersException(sprintf('The "%s" route has some missing mandatory parameters ("%s").', $name, implode('", "', array_keys($diff))));
+        }
+
+        $url = '';
+        $optional = true;
+        foreach ($tokens as $token) {
+            if ('variable' === $token[0]) {
+                if (false === $optional || !array_key_exists($token[3], $defaults) || (isset($parameters[$token[3]]) && (string) $parameters[$token[3]] != (string) $defaults[$token[3]])) {
+                    if (!$isEmpty = in_array($tparams[$token[3]], array(null, '', false), true)) {
+                        // check requirement
+                        if ($tparams[$token[3]] && !preg_match('#^'.$token[2].'$#', $tparams[$token[3]])) {
+                            throw new InvalidParameterException(sprintf('Parameter "%s" for route "%s" must match "%s" ("%s" given).', $token[3], $name, $token[2], $tparams[$token[3]]));
+                        }
+                    }
+
+                    if (!$isEmpty || !$optional) {
+                        $url = $token[1].strtr(rawurlencode($tparams[$token[3]]), $this->decodedChars).$url;
+                    }
+
+                    $optional = false;
+                }
+            } elseif ('text' === $token[0]) {
+                $url = $token[1].$url;
+                $optional = false;
+            }
+        }
+
+        if (!$url) {
+            $url = '/';
+        }
+
+        // add a query string if needed
+        $extra = array_diff_key($originParameters, $variables, $defaults);
+        if ($extra && $query = http_build_query($extra, '', '&')) {
+            $url .= '?'.$query;
+        }
+
+        $url = $this->context->getBaseUrl().$url;
+
+        if ($this->context->getHost()) {
+            $scheme = $this->context->getScheme();
+            if (isset($requirements['_scheme']) && ($req = strtolower($requirements['_scheme'])) && $scheme != $req) {
+                $absolute = true;
+                $scheme = $req;
+            }
+
+            if ($absolute) {
+                $port = '';
+                if ('http' === $scheme && 80 != $this->context->getHttpPort()) {
+                    $port = ':'.$this->context->getHttpPort();
+                } elseif ('https' === $scheme && 443 != $this->context->getHttpsPort()) {
+                    $port = ':'.$this->context->getHttpsPort();
+                }
+
+                $url = $scheme.'://'.$this->context->getHost().$port.$url;
+            }
+        }
+
+        return $url;
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php
new file mode 100644 (file)
index 0000000..6f2800c
--- /dev/null
@@ -0,0 +1,37 @@
+<?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\Generator;
+
+use Symfony\Component\Routing\RequestContextAwareInterface;
+
+/**
+ * UrlGeneratorInterface is the interface that all URL generator classes must implements.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @api
+ */
+interface UrlGeneratorInterface extends RequestContextAwareInterface
+{
+    /**
+     * Generates a URL from the given parameters.
+     *
+     * @param string  $name       The name of the route
+     * @param mixed   $parameters An array of parameters
+     * @param Boolean $absolute   Whether to generate an absolute URL
+     *
+     * @return string The generated URL
+     *
+     * @api
+     */
+    public function generate($name, $parameters = array(), $absolute = false);
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/LICENSE b/3rdparty/symfony/routing/Symfony/Component/Routing/LICENSE
new file mode 100644 (file)
index 0000000..cdffe7a
--- /dev/null
@@ -0,0 +1,19 @@
+Copyright (c) 2004-2012 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
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Loader/AnnotationClassLoader.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Loader/AnnotationClassLoader.php
new file mode 100644 (file)
index 0000000..5f292d4
--- /dev/null
@@ -0,0 +1,213 @@
+<?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 Doctrine\Common\Annotations\Reader;
+use Symfony\Component\Config\Resource\FileResource;
+use Symfony\Component\Routing\Route;
+use Symfony\Component\Routing\RouteCollection;
+use Symfony\Component\Config\Loader\LoaderInterface;
+use Symfony\Component\Config\Loader\LoaderResolver;
+
+/**
+ * AnnotationClassLoader loads routing information from a PHP class and its methods.
+ *
+ * You need to define an implementation for the getRouteDefaults() method. Most of the
+ * time, this method should define some PHP callable to be called for the route
+ * (a controller in MVC speak).
+ *
+ * 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:
+ *
+ *     /**
+ *      * @Route("/Blog")
+ *      * /
+ *     class Blog
+ *     {
+ *         /**
+ *          * @Route("/", name="blog_index")
+ *          * /
+ *         public function index()
+ *         {
+ *         }
+ *
+ *         /**
+ *          * @Route("/{id}", name="blog_post", requirements = {"id" = "\d+"})
+ *          * /
+ *         public function show()
+ *         {
+ *         }
+ *     }
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+abstract class AnnotationClassLoader implements LoaderInterface
+{
+    protected $reader;
+    protected $routeAnnotationClass  = 'Symfony\\Component\\Routing\\Annotation\\Route';
+    protected $defaultRouteIndex;
+
+    /**
+     * Constructor.
+     *
+     * @param Reader $reader
+     */
+    public function __construct(Reader $reader)
+    {
+        $this->reader = $reader;
+    }
+
+    /**
+     * Sets the annotation class to read route properties from.
+     *
+     * @param string $class A fully-qualified class name
+     */
+    public function setRouteAnnotationClass($class)
+    {
+        $this->routeAnnotationClass = $class;
+    }
+
+    /**
+     * Loads from annotations from a class.
+     *
+     * @param string $class A class name
+     * @param string $type  The resource type
+     *
+     * @return RouteCollection A RouteCollection instance
+     *
+     * @throws \InvalidArgumentException When route can't be parsed
+     */
+    public function load($class, $type = null)
+    {
+        if (!class_exists($class)) {
+            throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
+        }
+
+        $globals = array(
+            'pattern'      => '',
+            'requirements' => array(),
+            'options'      => array(),
+            'defaults'     => array(),
+        );
+
+        $class = new \ReflectionClass($class);
+        if ($class->isAbstract()) {
+            throw new \InvalidArgumentException(sprintf('Annotations from class "%s" cannot be read as it is abstract.', $class));
+        }
+
+        if ($annot = $this->reader->getClassAnnotation($class, $this->routeAnnotationClass)) {
+            if (null !== $annot->getPattern()) {
+                $globals['pattern'] = $annot->getPattern();
+            }
+
+            if (null !== $annot->getRequirements()) {
+                $globals['requirements'] = $annot->getRequirements();
+            }
+
+            if (null !== $annot->getOptions()) {
+                $globals['options'] = $annot->getOptions();
+            }
+
+            if (null !== $annot->getDefaults()) {
+                $globals['defaults'] = $annot->getDefaults();
+            }
+        }
+
+        $collection = new RouteCollection();
+        $collection->addResource(new FileResource($class->getFileName()));
+
+        foreach ($class->getMethods() as $method) {
+            $this->defaultRouteIndex = 0;
+            foreach ($this->reader->getMethodAnnotations($method) as $annot) {
+                if ($annot instanceof $this->routeAnnotationClass) {
+                    $this->addRoute($collection, $annot, $globals, $class, $method);
+                }
+            }
+        }
+
+        return $collection;
+    }
+
+    protected function addRoute(RouteCollection $collection, $annot, $globals, \ReflectionClass $class, \ReflectionMethod $method)
+    {
+        $name = $annot->getName();
+        if (null === $name) {
+            $name = $this->getDefaultRouteName($class, $method);
+        }
+
+        $defaults = array_merge($globals['defaults'], $annot->getDefaults());
+        $requirements = array_merge($globals['requirements'], $annot->getRequirements());
+        $options = array_merge($globals['options'], $annot->getOptions());
+
+        $route = new Route($globals['pattern'].$annot->getPattern(), $defaults, $requirements, $options);
+
+        $this->configureRoute($route, $class, $method, $annot);
+
+        $collection->add($name, $route);
+    }
+
+    /**
+     * Returns true if this class supports the given resource.
+     *
+     * @param mixed  $resource A resource
+     * @param string $type     The resource type
+     *
+     * @return Boolean True if this class supports the given resource, false otherwise
+     */
+    public function supports($resource, $type = null)
+    {
+        return is_string($resource) && preg_match('/^(?:\\\\?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)+$/', $resource) && (!$type || 'annotation' === $type);
+    }
+
+    /**
+     * Sets the loader resolver.
+     *
+     * @param LoaderResolver $resolver A LoaderResolver instance
+     */
+    public function setResolver(LoaderResolver $resolver)
+    {
+    }
+
+    /**
+     * Gets the loader resolver.
+     *
+     * @return LoaderResolver A LoaderResolver instance
+     */
+    public function getResolver()
+    {
+    }
+
+    /**
+     * Gets the default route name for a class method.
+     *
+     * @param \ReflectionClass  $class
+     * @param \ReflectionMethod $method
+     *
+     * @return string
+     */
+    protected function getDefaultRouteName(\ReflectionClass $class, \ReflectionMethod $method)
+    {
+        $name = strtolower(str_replace('\\', '_', $class->name).'_'.$method->name);
+        if ($this->defaultRouteIndex > 0) {
+            $name .= '_'.$this->defaultRouteIndex;
+        }
+        $this->defaultRouteIndex++;
+
+        return $name;
+    }
+
+    abstract protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, $annot);
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php
new file mode 100644 (file)
index 0000000..8097cd6
--- /dev/null
@@ -0,0 +1,77 @@
+<?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\Routing\RouteCollection;
+use Symfony\Component\Config\Resource\DirectoryResource;
+
+/**
+ * AnnotationDirectoryLoader loads routing information from annotations set
+ * on PHP classes and methods.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class AnnotationDirectoryLoader extends AnnotationFileLoader
+{
+    /**
+     * Loads from annotations from a directory.
+     *
+     * @param string $path A directory path
+     * @param string $type The resource type
+     *
+     * @return RouteCollection A RouteCollection instance
+     *
+     * @throws \InvalidArgumentException When the directory does not exist or its routes cannot be parsed
+     */
+    public function load($path, $type = null)
+    {
+        $dir = $this->locator->locate($path);
+
+        $collection = new RouteCollection();
+        $collection->addResource(new DirectoryResource($dir, '/\.php$/'));
+        foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
+            if (!$file->isFile() || '.php' !== substr($file->getFilename(), -4)) {
+                continue;
+            }
+
+            if ($class = $this->findClass($file)) {
+                $refl = new \ReflectionClass($class);
+                if ($refl->isAbstract()) {
+                    continue;
+                }
+
+                $collection->addCollection($this->loader->load($class, $type));
+            }
+        }
+
+        return $collection;
+    }
+
+    /**
+     * Returns true if this class supports the given resource.
+     *
+     * @param mixed  $resource A resource
+     * @param string $type     The resource type
+     *
+     * @return Boolean True if this class supports the given resource, false otherwise
+     */
+    public function supports($resource, $type = null)
+    {
+        try {
+            $path = $this->locator->locate($resource);
+        } catch (\Exception $e) {
+            return false;
+        }
+
+        return is_string($resource) && is_dir($path) && (!$type || 'annotation' === $type);
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Loader/AnnotationFileLoader.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Loader/AnnotationFileLoader.php
new file mode 100644 (file)
index 0000000..49e1cb2
--- /dev/null
@@ -0,0 +1,125 @@
+<?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\Routing\RouteCollection;
+use Symfony\Component\Config\Resource\FileResource;
+use Symfony\Component\Config\Loader\FileLoader;
+use Symfony\Component\Config\FileLocator;
+
+/**
+ * AnnotationFileLoader loads routing information from annotations set
+ * on a PHP class and its methods.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class AnnotationFileLoader extends FileLoader
+{
+    protected $loader;
+
+    /**
+     * Constructor.
+     *
+     * @param FileLocator           $locator A FileLocator instance
+     * @param AnnotationClassLoader $loader  An AnnotationClassLoader instance
+     * @param string|array          $paths   A path or an array of paths where to look for resources
+     */
+    public function __construct(FileLocator $locator, AnnotationClassLoader $loader, $paths = array())
+    {
+        if (!function_exists('token_get_all')) {
+            throw new \RuntimeException('The Tokenizer extension is required for the routing annotation loaders.');
+        }
+
+        parent::__construct($locator, $paths);
+
+        $this->loader = $loader;
+    }
+
+    /**
+     * Loads from annotations from a file.
+     *
+     * @param string $file A PHP file path
+     * @param string $type The resource type
+     *
+     * @return RouteCollection A RouteCollection instance
+     *
+     * @throws \InvalidArgumentException When the file does not exist or its routes cannot be parsed
+     */
+    public function load($file, $type = null)
+    {
+        $path = $this->locator->locate($file);
+
+        $collection = new RouteCollection();
+        if ($class = $this->findClass($path)) {
+            $collection->addResource(new FileResource($path));
+            $collection->addCollection($this->loader->load($class, $type));
+        }
+
+        return $collection;
+    }
+
+    /**
+     * Returns true if this class supports the given resource.
+     *
+     * @param mixed  $resource A resource
+     * @param string $type     The resource type
+     *
+     * @return Boolean True if this class supports the given resource, false otherwise
+     */
+    public function supports($resource, $type = null)
+    {
+        return is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'annotation' === $type);
+    }
+
+    /**
+     * Returns the full class name for the first class in the file.
+     *
+     * @param string $file A PHP file path
+     *
+     * @return string|false Full class name if found, false otherwise
+     */
+    protected function findClass($file)
+    {
+        $class = false;
+        $namespace = false;
+        $tokens = token_get_all(file_get_contents($file));
+        for ($i = 0, $count = count($tokens); $i < $count; $i++) {
+            $token = $tokens[$i];
+
+            if (!is_array($token)) {
+                continue;
+            }
+
+            if (true === $class && T_STRING === $token[0]) {
+                return $namespace.'\\'.$token[1];
+            }
+
+            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)));
+            }
+
+            if (T_CLASS === $token[0]) {
+                $class = true;
+            }
+
+            if (T_NAMESPACE === $token[0]) {
+                $namespace = true;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Loader/ClosureLoader.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Loader/ClosureLoader.php
new file mode 100644 (file)
index 0000000..ca49c8f
--- /dev/null
@@ -0,0 +1,54 @@
+<?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;
+
+/**
+ * ClosureLoader loads routes from a PHP closure.
+ *
+ * The Closure must return a RouteCollection instance.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @api
+ */
+class ClosureLoader extends Loader
+{
+    /**
+     * Loads a Closure.
+     *
+     * @param \Closure $closure A Closure
+     * @param string   $type    The resource type
+     *
+     * @api
+     */
+    public function load($closure, $type = null)
+    {
+        return call_user_func($closure);
+    }
+
+    /**
+     * Returns true if this class supports the given resource.
+     *
+     * @param mixed  $resource A resource
+     * @param string $type     The resource type
+     *
+     * @return Boolean True if this class supports the given resource, false otherwise
+     *
+     * @api
+     */
+    public function supports($resource, $type = null)
+    {
+        return $resource instanceof \Closure && (!$type || 'closure' === $type);
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Loader/PhpFileLoader.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Loader/PhpFileLoader.php
new file mode 100644 (file)
index 0000000..ffd31f9
--- /dev/null
@@ -0,0 +1,64 @@
+<?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\Resource\FileResource;
+use Symfony\Component\Config\Loader\FileLoader;
+
+/**
+ * PhpFileLoader loads routes from a PHP file.
+ *
+ * The file must return a RouteCollection instance.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @api
+ */
+class PhpFileLoader extends FileLoader
+{
+    /**
+     * Loads a PHP file.
+     *
+     * @param mixed  $file A PHP file path
+     * @param string $type The resource type
+     *
+     * @api
+     */
+    public function load($file, $type = null)
+    {
+        // the loader variable is exposed to the included file below
+        $loader = $this;
+
+        $path = $this->locator->locate($file);
+        $this->setCurrentDir(dirname($path));
+
+        $collection = include $path;
+        $collection->addResource(new FileResource($path));
+
+        return $collection;
+    }
+
+    /**
+     * Returns true if this class supports the given resource.
+     *
+     * @param mixed  $resource A resource
+     * @param string $type     The resource type
+     *
+     * @return Boolean True if this class supports the given resource, false otherwise
+     *
+     * @api
+     */
+    public function supports($resource, $type = null)
+    {
+        return is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'php' === $type);
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Loader/XmlFileLoader.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Loader/XmlFileLoader.php
new file mode 100644 (file)
index 0000000..5dad9db
--- /dev/null
@@ -0,0 +1,224 @@
+<?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\Routing\RouteCollection;
+use Symfony\Component\Routing\Route;
+use Symfony\Component\Config\Resource\FileResource;
+use Symfony\Component\Config\Loader\FileLoader;
+
+/**
+ * XmlFileLoader loads XML routing files.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @api
+ */
+class XmlFileLoader extends FileLoader
+{
+    /**
+     * Loads an XML file.
+     *
+     * @param string $file An XML file path
+     * @param string $type The resource type
+     *
+     * @return RouteCollection A RouteCollection instance
+     *
+     * @throws \InvalidArgumentException When a tag can't be parsed
+     *
+     * @api
+     */
+    public function load($file, $type = null)
+    {
+        $path = $this->locator->locate($file);
+
+        $xml = $this->loadFile($path);
+
+        $collection = new RouteCollection();
+        $collection->addResource(new FileResource($path));
+
+        // process routes and imports
+        foreach ($xml->documentElement->childNodes as $node) {
+            if (!$node instanceof \DOMElement) {
+                continue;
+            }
+
+            $this->parseNode($collection, $node, $path, $file);
+        }
+
+        return $collection;
+    }
+
+    /**
+     * Parses a node from a loaded XML file.
+     *
+     * @param RouteCollection $collection the collection to associate with the node
+     * @param DOMElement      $node       the node to parse
+     * @param string          $path       the path of the XML file being processed
+     * @param string          $file
+     */
+    protected function parseNode(RouteCollection $collection, \DOMElement $node, $path, $file)
+    {
+        switch ($node->tagName) {
+            case 'route':
+                $this->parseRoute($collection, $node, $path);
+                break;
+            case 'import':
+                $resource = (string) $node->getAttribute('resource');
+                $type = (string) $node->getAttribute('type');
+                $prefix = (string) $node->getAttribute('prefix');
+                $this->setCurrentDir(dirname($path));
+                $collection->addCollection($this->import($resource, ('' !== $type ? $type : null), false, $file), $prefix);
+                break;
+            default:
+                throw new \InvalidArgumentException(sprintf('Unable to parse tag "%s"', $node->tagName));
+        }
+    }
+
+    /**
+     * Returns true if this class supports the given resource.
+     *
+     * @param mixed  $resource A resource
+     * @param string $type     The resource type
+     *
+     * @return Boolean True if this class supports the given resource, false otherwise
+     *
+     * @api
+     */
+    public function supports($resource, $type = null)
+    {
+        return is_string($resource) && 'xml' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'xml' === $type);
+    }
+
+    /**
+     * Parses a route and adds it to the RouteCollection.
+     *
+     * @param RouteCollection $collection A RouteCollection instance
+     * @param \DOMElement     $definition Route definition
+     * @param string          $file       An XML file path
+     *
+     * @throws \InvalidArgumentException When the definition cannot be parsed
+     */
+    protected function parseRoute(RouteCollection $collection, \DOMElement $definition, $file)
+    {
+        $defaults = array();
+        $requirements = array();
+        $options = array();
+
+        foreach ($definition->childNodes as $node) {
+            if (!$node instanceof \DOMElement) {
+                continue;
+            }
+
+            switch ($node->tagName) {
+                case 'default':
+                    $defaults[(string) $node->getAttribute('key')] = trim((string) $node->nodeValue);
+                    break;
+                case 'option':
+                    $options[(string) $node->getAttribute('key')] = trim((string) $node->nodeValue);
+                    break;
+                case 'requirement':
+                    $requirements[(string) $node->getAttribute('key')] = trim((string) $node->nodeValue);
+                    break;
+                default:
+                    throw new \InvalidArgumentException(sprintf('Unable to parse tag "%s"', $node->tagName));
+            }
+        }
+
+        $route = new Route((string) $definition->getAttribute('pattern'), $defaults, $requirements, $options);
+
+        $collection->add((string) $definition->getAttribute('id'), $route);
+    }
+
+    /**
+     * Loads an XML file.
+     *
+     * @param string $file An XML file path
+     *
+     * @return \DOMDocument
+     *
+     * @throws \InvalidArgumentException When loading of XML file returns error
+     */
+    protected function loadFile($file)
+    {
+        $internalErrors = libxml_use_internal_errors(true);
+        $disableEntities = libxml_disable_entity_loader(true);
+        libxml_clear_errors();
+
+        $dom = new \DOMDocument();
+        $dom->validateOnParse = true;
+        if (!$dom->loadXML(file_get_contents($file), LIBXML_NONET | (defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0))) {
+            libxml_disable_entity_loader($disableEntities);
+
+            throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors($internalErrors)));
+        }
+        $dom->normalizeDocument();
+
+        libxml_use_internal_errors($internalErrors);
+        libxml_disable_entity_loader($disableEntities);
+
+        foreach ($dom->childNodes as $child) {
+            if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
+                throw new \InvalidArgumentException('Document types are not allowed.');
+            }
+        }
+
+        $this->validate($dom);
+
+        return $dom;
+    }
+
+    /**
+     * Validates a loaded XML file.
+     *
+     * @param \DOMDocument $dom A loaded XML file
+     *
+     * @throws \InvalidArgumentException When XML doesn't validate its XSD schema
+     */
+    protected function validate(\DOMDocument $dom)
+    {
+        $location = __DIR__.'/schema/routing/routing-1.0.xsd';
+
+        $current = libxml_use_internal_errors(true);
+        libxml_clear_errors();
+
+        if (!$dom->schemaValidate($location)) {
+            throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors($current)));
+        }
+        libxml_use_internal_errors($current);
+    }
+
+    /**
+     * Retrieves libxml errors and clears them.
+     *
+     * @return array An array of libxml error strings
+     */
+    private function getXmlErrors($internalErrors)
+    {
+        $errors = array();
+        foreach (libxml_get_errors() as $error) {
+            $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
+                LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
+                $error->code,
+                trim($error->message),
+                $error->file ? $error->file : 'n/a',
+                $error->line,
+                $error->column
+            );
+        }
+
+        libxml_clear_errors();
+        libxml_use_internal_errors($internalErrors);
+
+        return $errors;
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Loader/YamlFileLoader.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Loader/YamlFileLoader.php
new file mode 100644 (file)
index 0000000..ee72383
--- /dev/null
@@ -0,0 +1,142 @@
+<?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\Routing\RouteCollection;
+use Symfony\Component\Routing\Route;
+use Symfony\Component\Config\Resource\FileResource;
+use Symfony\Component\Yaml\Yaml;
+use Symfony\Component\Config\Loader\FileLoader;
+
+/**
+ * YamlFileLoader loads Yaml routing files.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @api
+ */
+class YamlFileLoader extends FileLoader
+{
+    private static $availableKeys = array(
+        'type', 'resource', 'prefix', 'pattern', 'options', 'defaults', 'requirements'
+    );
+
+    /**
+     * Loads a Yaml file.
+     *
+     * @param string $file A Yaml file path
+     * @param string $type The resource type
+     *
+     * @return RouteCollection A RouteCollection instance
+     *
+     * @throws \InvalidArgumentException When route can't be parsed
+     *
+     * @api
+     */
+    public function load($file, $type = null)
+    {
+        $path = $this->locator->locate($file);
+
+        $config = Yaml::parse($path);
+
+        $collection = new RouteCollection();
+        $collection->addResource(new FileResource($path));
+
+        // empty file
+        if (null === $config) {
+            $config = array();
+        }
+
+        // not an array
+        if (!is_array($config)) {
+            throw new \InvalidArgumentException(sprintf('The file "%s" must contain a YAML array.', $file));
+        }
+
+        foreach ($config as $name => $config) {
+            $config = $this->normalizeRouteConfig($config);
+
+            if (isset($config['resource'])) {
+                $type = isset($config['type']) ? $config['type'] : null;
+                $prefix = isset($config['prefix']) ? $config['prefix'] : null;
+                $this->setCurrentDir(dirname($path));
+                $collection->addCollection($this->import($config['resource'], $type, false, $file), $prefix);
+            } else {
+                $this->parseRoute($collection, $name, $config, $path);
+            }
+        }
+
+        return $collection;
+    }
+
+    /**
+     * Returns true if this class supports the given resource.
+     *
+     * @param mixed  $resource A resource
+     * @param string $type     The resource type
+     *
+     * @return Boolean True if this class supports the given resource, false otherwise
+     *
+     * @api
+     */
+    public function supports($resource, $type = null)
+    {
+        return is_string($resource) && 'yml' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'yaml' === $type);
+    }
+
+    /**
+     * Parses a route and adds it to the RouteCollection.
+     *
+     * @param RouteCollection $collection A RouteCollection instance
+     * @param string          $name       Route name
+     * @param array           $config     Route definition
+     * @param string          $file       A Yaml file path
+     *
+     * @throws \InvalidArgumentException When config pattern is not defined for the given route
+     */
+    protected function parseRoute(RouteCollection $collection, $name, $config, $file)
+    {
+        $defaults = isset($config['defaults']) ? $config['defaults'] : array();
+        $requirements = isset($config['requirements']) ? $config['requirements'] : array();
+        $options = isset($config['options']) ? $config['options'] : array();
+
+        if (!isset($config['pattern'])) {
+            throw new \InvalidArgumentException(sprintf('You must define a "pattern" for the "%s" route.', $name));
+        }
+
+        $route = new Route($config['pattern'], $defaults, $requirements, $options);
+
+        $collection->add($name, $route);
+    }
+
+    /**
+     * Normalize route configuration.
+     *
+     * @param array $config A resource config
+     *
+     * @return array
+     *
+     * @throws InvalidArgumentException if one of the provided config keys is not supported
+     */
+    private function normalizeRouteConfig(array $config)
+    {
+        foreach ($config as $key => $value) {
+            if (!in_array($key, self::$availableKeys)) {
+                throw new \InvalidArgumentException(sprintf(
+                    'Yaml routing loader does not support given key: "%s". Expected one of the (%s).',
+                    $key, implode(', ', self::$availableKeys)
+                ));
+            }
+        }
+
+        return $config;
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd b/3rdparty/symfony/routing/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd
new file mode 100644 (file)
index 0000000..a9554e6
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<xsd:schema xmlns="http://symfony.com/schema/routing"
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    targetNamespace="http://symfony.com/schema/routing"
+    elementFormDefault="qualified">
+
+  <xsd:element name="routes" type="routes" />
+
+  <xsd:complexType name="routes">
+    <xsd:choice maxOccurs="unbounded" minOccurs="0">
+      <xsd:element name="import" type="import" />
+      <xsd:element name="route" type="route" />
+    </xsd:choice>
+  </xsd:complexType>
+
+  <xsd:complexType name="route">
+    <xsd:sequence>
+      <xsd:element name="default" type="element" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="requirement" type="element" minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element name="option" type="element" minOccurs="0" maxOccurs="unbounded" />
+    </xsd:sequence>
+
+    <xsd:attribute name="id" type="xsd:string" />
+    <xsd:attribute name="pattern" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="import">
+    <xsd:attribute name="resource" type="xsd:string" />
+    <xsd:attribute name="type" type="xsd:string" />
+    <xsd:attribute name="prefix" type="xsd:string" />
+    <xsd:attribute name="class" type="xsd:string" />
+  </xsd:complexType>
+
+  <xsd:complexType name="element" mixed="true">
+    <xsd:attribute name="key" type="xsd:string" />
+  </xsd:complexType>
+</xsd:schema>
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/ApacheUrlMatcher.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/ApacheUrlMatcher.php
new file mode 100644 (file)
index 0000000..3003dfd
--- /dev/null
@@ -0,0 +1,76 @@
+<?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).
+ *
+ * @author Fabien Potencier <fabien@symfony.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();
+        $match = false;
+
+        foreach ($_SERVER as $key => $value) {
+            $name = $key;
+
+            if (0 === strpos($name, 'REDIRECT_')) {
+                $name = substr($name, 9);
+            }
+
+            if (0 === strpos($name, '_ROUTING_DEFAULTS_')) {
+                $name = substr($name, 18);
+                $defaults[$name] = $value;
+            } elseif (0 === strpos($name, '_ROUTING_')) {
+                $name = substr($name, 9);
+                if ('_route' == $name) {
+                    $match = true;
+                    $parameters[$name] = $value;
+                } elseif (0 === strpos($name, '_allow_')) {
+                    $allow[] = substr($name, 7);
+                } else {
+                    $parameters[$name] = $value;
+                }
+            } else {
+                continue;
+            }
+
+            unset($_SERVER[$key]);
+        }
+
+        if ($match) {
+            return $this->mergeDefaults($parameters, $defaults);
+        } elseif (0 < count($allow)) {
+            throw new MethodNotAllowedException($allow);
+        } else {
+            return parent::match($pathinfo);
+        }
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php
new file mode 100644 (file)
index 0000000..4f03b8d
--- /dev/null
@@ -0,0 +1,155 @@
+<?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;
+
+/**
+ * Dumps a set of Apache mod_rewrite rules.
+ *
+ * @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();
+
+        foreach ($this->getRoutes()->all() as $name => $route) {
+            $compiledRoute = $route->compile();
+
+            // prepare the apache regex
+            $regex = $compiledRoute->getRegex();
+            $delimiter = $regex[0];
+            $regexPatternEnd = strrpos($regex, $delimiter);
+            if (strlen($regex) < 2 || 0 === $regexPatternEnd) {
+                throw new \LogicException('The "%s" route regex "%s" is invalid', $name, $regex);
+            }
+            $regex = preg_replace('/\?P<.+?>/', '', substr($regex, 1, $regexPatternEnd - 1));
+            $regex = '^'.self::escape(preg_quote($options['base_uri']).substr($regex, 1), ' ', '\\');
+
+            $hasTrailingSlash = '/$' == substr($regex, -2) && '^/$' != $regex;
+
+            $variables = array('E=_ROUTING__route:'.$name);
+            foreach ($compiledRoute->getVariables() as $i => $variable) {
+                $variables[] = 'E=_ROUTING_'.$variable.':%'.($i + 1);
+            }
+            foreach ($route->getDefaults() as $key => $value) {
+                $variables[] = 'E=_ROUTING_DEFAULTS_'.$key.':'.strtr($value, array(
+                    ':'  => '\\:',
+                    '='  => '\\=',
+                    '\\' => '\\\\',
+                    ' '  => '\\ ',
+                ));
+            }
+            $variables = implode(',', $variables);
+
+            $rule = array("# $name");
+
+            // method mismatch
+            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';
+                }
+                $allow = array();
+                foreach ($methods as $method) {
+                    $methodVars[] = $method;
+                    $allow[] = 'E=_ROUTING__allow_'.$method.':1';
+                }
+
+                $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) {
+                $rule[] = 'RewriteCond %{REQUEST_URI} '.substr($regex, 0, -2).'$';
+                $rule[] = 'RewriteRule .* $0/ [QSA,L,R=301]';
+            }
+
+            // the main rule
+            $rule[] = "RewriteCond %{REQUEST_URI} $regex";
+            $rule[] = "RewriteRule .* {$options['script_name']} [QSA,L,$variables]";
+
+            $rules[] = implode("\n", $rule);
+        }
+
+        if (0 < count($methodVars)) {
+            $rule = array('# 405 Method Not Allowed');
+            $methodVars = array_values(array_unique($methodVars));
+            foreach ($methodVars as $i => $methodVar) {
+                $rule[] = sprintf('RewriteCond %%{_ROUTING__allow_%s} !-z%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";
+    }
+
+    /**
+     * 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;
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumper.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumper.php
new file mode 100644 (file)
index 0000000..423368b
--- /dev/null
@@ -0,0 +1,44 @@
+<?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\RouteCollection;
+
+/**
+ * MatcherDumper is the abstract class for all built-in matcher dumpers.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+abstract class MatcherDumper implements MatcherDumperInterface
+{
+    private $routes;
+
+    /**
+     * Constructor.
+     *
+     * @param RouteCollection $routes The RouteCollection to dump
+     */
+    public function __construct(RouteCollection $routes)
+    {
+        $this->routes = $routes;
+    }
+
+    /**
+     * Gets the routes to dump.
+     *
+     * @return RouteCollection A RouteCollection instance
+     */
+    public function getRoutes()
+    {
+        return $this->routes;
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumperInterface.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumperInterface.php
new file mode 100644 (file)
index 0000000..fe09e06
--- /dev/null
@@ -0,0 +1,41 @@
+<?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;
+
+/**
+ * MatcherDumperInterface is the interface that all matcher dumper classes must implement.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+interface MatcherDumperInterface
+{
+    /**
+     * Dumps a set of routes to a PHP class.
+     *
+     * Available options:
+     *
+     *  * class:      The class name
+     *  * base_class: The base class name
+     *
+     * @param array $options An array of options
+     *
+     * @return string A PHP class representing the matcher class
+     */
+    public function dump(array $options = array());
+
+    /**
+     * Gets the routes to match.
+     *
+     * @return RouteCollection A RouteCollection instance
+     */
+    public function getRoutes();
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php
new file mode 100644 (file)
index 0000000..fdaad51
--- /dev/null
@@ -0,0 +1,293 @@
+<?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;
+use Symfony\Component\Routing\RouteCollection;
+
+/**
+ * PhpMatcherDumper creates a PHP class able to match URLs for a given set of routes.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class PhpMatcherDumper extends MatcherDumper
+{
+    /**
+     * Dumps a set of routes to a PHP class.
+     *
+     * Available options:
+     *
+     *  * class:      The class name
+     *  * base_class: The base class name
+     *
+     * @param array $options An array of options
+     *
+     * @return string A PHP class representing the matcher class
+     */
+    public function dump(array $options = array())
+    {
+        $options = array_merge(array(
+            'class'      => 'ProjectUrlMatcher',
+            'base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
+        ), $options);
+
+        // trailing slash support is only enabled if we know how to redirect the user
+        $interfaces = class_implements($options['base_class']);
+        $supportsRedirections = isset($interfaces['Symfony\Component\Routing\Matcher\RedirectableUrlMatcherInterface']);
+
+        return
+            $this->startClass($options['class'], $options['base_class']).
+            $this->addConstructor().
+            $this->addMatcher($supportsRedirections).
+            $this->endClass()
+        ;
+    }
+
+    private function addMatcher($supportsRedirections)
+    {
+        // we need to deep clone the routes as we will modify the structure to optimize the dump
+        $code = implode("\n", $this->compileRoutes(clone $this->getRoutes(), $supportsRedirections));
+
+        return <<<EOF
+
+    public function match(\$pathinfo)
+    {
+        \$allow = array();
+        \$pathinfo = urldecode(\$pathinfo);
+
+$code
+        throw 0 < count(\$allow) ? new MethodNotAllowedException(array_unique(\$allow)) : new ResourceNotFoundException();
+    }
+
+EOF;
+    }
+
+    private function compileRoutes(RouteCollection $routes, $supportsRedirections, $parentPrefix = null)
+    {
+        $code = array();
+
+        $routeIterator = $routes->getIterator();
+        $keys = array_keys($routeIterator->getArrayCopy());
+        $keysCount = count($keys);
+
+        $i = 0;
+        foreach ($routeIterator as $name => $route) {
+            $i++;
+
+            if ($route instanceof RouteCollection) {
+                $prefix = $route->getPrefix();
+                $optimizable = $prefix && count($route->all()) > 1 && false === strpos($route->getPrefix(), '{');
+                $indent = '';
+                if ($optimizable) {
+                    for ($j = $i; $j < $keysCount; $j++) {
+                        if ($keys[$j] === null) {
+                            continue;
+                        }
+
+                        $testRoute = $routeIterator->offsetGet($keys[$j]);
+                        $isCollection = ($testRoute instanceof RouteCollection);
+
+                        $testPrefix = $isCollection ? $testRoute->getPrefix() : $testRoute->getPattern();
+
+                        if (0 === strpos($testPrefix, $prefix)) {
+                            $routeIterator->offsetUnset($keys[$j]);
+
+                            if ($isCollection) {
+                                $route->addCollection($testRoute);
+                            } else {
+                                $route->add($keys[$j], $testRoute);
+                            }
+
+                            $i++;
+                            $keys[$j] = null;
+                        }
+                    }
+
+                    if ($prefix !== $parentPrefix) {
+                        $code[] = sprintf("        if (0 === strpos(\$pathinfo, %s)) {", var_export($prefix, true));
+                        $indent = '    ';
+                    }
+                }
+
+                foreach ($this->compileRoutes($route, $supportsRedirections, $prefix) as $line) {
+                    foreach (explode("\n", $line) as $l) {
+                        if ($l) {
+                            $code[] = $indent.$l;
+                        } else {
+                            $code[] = $l;
+                        }
+                    }
+                }
+
+                if ($optimizable && $prefix !== $parentPrefix) {
+                    $code[] = "        }\n";
+                }
+            } else {
+                foreach ($this->compileRoute($route, $name, $supportsRedirections, $parentPrefix) as $line) {
+                    $code[] = $line;
+                }
+            }
+        }
+
+        return $code;
+    }
+
+    private function compileRoute(Route $route, $name, $supportsRedirections, $parentPrefix = null)
+    {
+        $code = array();
+        $compiledRoute = $route->compile();
+        $conditions = array();
+        $hasTrailingSlash = false;
+        $matches = false;
+        if (!count($compiledRoute->getVariables()) && false !== preg_match('#^(.)\^(?P<url>.*?)\$\1#', $compiledRoute->getRegex(), $m)) {
+            if ($supportsRedirections && substr($m['url'], -1) === '/') {
+                $conditions[] = sprintf("rtrim(\$pathinfo, '/') === %s", var_export(rtrim(str_replace('\\', '', $m['url']), '/'), true));
+                $hasTrailingSlash = true;
+            } else {
+                $conditions[] = sprintf("\$pathinfo === %s", var_export(str_replace('\\', '', $m['url']), true));
+            }
+        } else {
+            if ($compiledRoute->getStaticPrefix() && $compiledRoute->getStaticPrefix() != $parentPrefix) {
+                $conditions[] = sprintf("0 === strpos(\$pathinfo, %s)", var_export($compiledRoute->getStaticPrefix(), true));
+            }
+
+            $regex = $compiledRoute->getRegex();
+            if ($supportsRedirections && $pos = strpos($regex, '/$')) {
+                $regex = substr($regex, 0, $pos).'/?$'.substr($regex, $pos + 2);
+                $hasTrailingSlash = true;
+            }
+            $conditions[] = sprintf("preg_match(%s, \$pathinfo, \$matches)", var_export($regex, true));
+
+            $matches = true;
+        }
+
+        $conditions = implode(' && ', $conditions);
+
+        $gotoname = 'not_'.preg_replace('/[^A-Za-z0-9_]/', '', $name);
+
+        $code[] = <<<EOF
+        // $name
+        if ($conditions) {
+EOF;
+
+        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';
+            }
+            if (1 === count($methods)) {
+                $code[] = <<<EOF
+            if (\$this->context->getMethod() != '$methods[0]') {
+                \$allow[] = '$methods[0]';
+                goto $gotoname;
+            }
+EOF;
+            } else {
+                $methods = implode('\', \'', $methods);
+                $code[] = <<<EOF
+            if (!in_array(\$this->context->getMethod(), array('$methods'))) {
+                \$allow = array_merge(\$allow, array('$methods'));
+                goto $gotoname;
+            }
+EOF;
+            }
+        }
+
+        if ($hasTrailingSlash) {
+            $code[] = sprintf(<<<EOF
+            if (substr(\$pathinfo, -1) !== '/') {
+                return \$this->redirect(\$pathinfo.'/', '%s');
+            }
+EOF
+            , $name);
+        }
+
+        if ($scheme = $route->getRequirement('_scheme')) {
+            if (!$supportsRedirections) {
+                throw new \LogicException('The "_scheme" requirement is only supported for route dumper that implements RedirectableUrlMatcherInterface.');
+            }
+
+            $code[] = sprintf(<<<EOF
+            if (\$this->context->getScheme() !== '$scheme') {
+                return \$this->redirect(\$pathinfo, '%s', '$scheme');
+            }
+EOF
+            , $name);
+        }
+
+        // optimize parameters array
+        if (true === $matches && $compiledRoute->getDefaults()) {
+            $code[] = sprintf("            return array_merge(\$this->mergeDefaults(\$matches, %s), array('_route' => '%s'));"
+                , str_replace("\n", '', var_export($compiledRoute->getDefaults(), true)), $name);
+        } elseif (true === $matches) {
+            $code[] = sprintf("            \$matches['_route'] = '%s';", $name);
+            $code[] = sprintf("            return \$matches;", $name);
+        } elseif ($compiledRoute->getDefaults()) {
+            $code[] = sprintf('            return %s;', str_replace("\n", '', var_export(array_merge($compiledRoute->getDefaults(), array('_route' => $name)), true)));
+        } else {
+            $code[] = sprintf("            return array('_route' => '%s');", $name);
+        }
+        $code[] = "        }";
+
+        if ($req) {
+            $code[] = "        $gotoname:";
+        }
+
+        $code[] = '';
+
+        return $code;
+    }
+
+    private function startClass($class, $baseClass)
+    {
+        return <<<EOF
+<?php
+
+use Symfony\Component\Routing\Exception\MethodNotAllowedException;
+use Symfony\Component\Routing\Exception\ResourceNotFoundException;
+use Symfony\Component\Routing\RequestContext;
+
+/**
+ * $class
+ *
+ * This class has been auto-generated
+ * by the Symfony Routing Component.
+ */
+class $class extends $baseClass
+{
+
+EOF;
+    }
+
+    private function addConstructor()
+    {
+        return <<<EOF
+    /**
+     * Constructor.
+     */
+    public function __construct(RequestContext \$context)
+    {
+        \$this->context = \$context;
+    }
+
+EOF;
+    }
+
+    private function endClass()
+    {
+        return <<<EOF
+}
+
+EOF;
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcher.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcher.php
new file mode 100644 (file)
index 0000000..fcd5880
--- /dev/null
@@ -0,0 +1,53 @@
+<?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\ResourceNotFoundException;
+
+/**
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @api
+ */
+abstract class RedirectableUrlMatcher extends UrlMatcher implements RedirectableUrlMatcherInterface
+{
+    private $trailingSlashTest = false;
+
+    /**
+     * @see UrlMatcher::match()
+     *
+     * @api
+     */
+    public function match($pathinfo)
+    {
+        try {
+            $parameters = parent::match($pathinfo);
+        } catch (ResourceNotFoundException $e) {
+            if ('/' === substr($pathinfo, -1)) {
+                throw $e;
+            }
+
+            // try with a / at the end
+            $this->trailingSlashTest = true;
+
+            return $this->match($pathinfo.'/');
+        }
+
+        if ($this->trailingSlashTest) {
+            $this->trailingSlashTest = false;
+
+            return $this->redirect($pathinfo, null);
+        }
+
+        return $parameters;
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcherInterface.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcherInterface.php
new file mode 100644 (file)
index 0000000..929ae9c
--- /dev/null
@@ -0,0 +1,35 @@
+<?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;
+
+/**
+ * RedirectableUrlMatcherInterface knows how to redirect the user.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @api
+ */
+interface RedirectableUrlMatcherInterface
+{
+    /**
+     * Redirects the user to another URL.
+     *
+     * @param string $path   The path info to redirect to.
+     * @param string $route  The route that matched
+     * @param string $scheme The URL scheme (null to keep the current one)
+     *
+     * @return array An array of parameters
+     *
+     * @api
+     */
+    public function redirect($path, $route, $scheme = null);
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcher.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcher.php
new file mode 100644 (file)
index 0000000..5ff8070
--- /dev/null
@@ -0,0 +1,151 @@
+<?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;
+use Symfony\Component\Routing\Exception\ResourceNotFoundException;
+use Symfony\Component\Routing\RouteCollection;
+use Symfony\Component\Routing\RequestContext;
+
+/**
+ * UrlMatcher matches URL based on a set of routes.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @api
+ */
+class UrlMatcher implements UrlMatcherInterface
+{
+    protected $context;
+    protected $allow;
+
+    private $routes;
+
+    /**
+     * Constructor.
+     *
+     * @param RouteCollection $routes  A RouteCollection instance
+     * @param RequestContext  $context The context
+     *
+     * @api
+     */
+    public function __construct(RouteCollection $routes, RequestContext $context)
+    {
+        $this->routes = $routes;
+        $this->context = $context;
+    }
+
+    /**
+     * Sets the request context.
+     *
+     * @param RequestContext $context The context
+     *
+     * @api
+     */
+    public function setContext(RequestContext $context)
+    {
+        $this->context = $context;
+    }
+
+    /**
+     * Gets the request context.
+     *
+     * @return RequestContext The context
+     */
+    public function getContext()
+    {
+        return $this->context;
+    }
+
+    /**
+     * Tries to match a URL with a set of routes.
+     *
+     * @param string $pathinfo The path info to be parsed
+     *
+     * @return array An array of parameters
+     *
+     * @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)
+    {
+        $this->allow = array();
+
+        if ($ret = $this->matchCollection($pathinfo, $this->routes)) {
+            return $ret;
+        }
+
+        throw 0 < count($this->allow)
+            ? new MethodNotAllowedException(array_unique(array_map('strtoupper', $this->allow)))
+            : new ResourceNotFoundException();
+    }
+
+    protected function matchCollection($pathinfo, RouteCollection $routes)
+    {
+        $pathinfo = urldecode($pathinfo);
+
+        foreach ($routes as $name => $route) {
+            if ($route instanceof RouteCollection) {
+                if (false === strpos($route->getPrefix(), '{') && $route->getPrefix() !== substr($pathinfo, 0, strlen($route->getPrefix()))) {
+                    continue;
+                }
+
+                if (!$ret = $this->matchCollection($pathinfo, $route)) {
+                    continue;
+                }
+
+                return $ret;
+            }
+
+            $compiledRoute = $route->compile();
+
+            // check the static prefix of the URL first. Only use the more expensive preg_match when it matches
+            if ('' !== $compiledRoute->getStaticPrefix() && 0 !== strpos($pathinfo, $compiledRoute->getStaticPrefix())) {
+                continue;
+            }
+
+            if (!preg_match($compiledRoute->getRegex(), $pathinfo, $matches)) {
+                continue;
+            }
+
+            // check HTTP method requirement
+            if ($req = $route->getRequirement('_method')) {
+                // 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);
+
+                    continue;
+                }
+            }
+
+            return array_merge($this->mergeDefaults($matches, $route->getDefaults()), array('_route' => $name));
+        }
+    }
+
+    protected function mergeDefaults($params, $defaults)
+    {
+        $parameters = $defaults;
+        foreach ($params as $key => $value) {
+            if (!is_int($key)) {
+                $parameters[$key] = rawurldecode($value);
+            }
+        }
+
+        return $parameters;
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcherInterface.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcherInterface.php
new file mode 100644 (file)
index 0000000..5823d32
--- /dev/null
@@ -0,0 +1,38 @@
+<?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\RequestContextAwareInterface;
+
+/**
+ * UrlMatcherInterface is the interface that all URL matcher classes must implement.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @api
+ */
+interface UrlMatcherInterface extends RequestContextAwareInterface
+{
+    /**
+     * Tries to match a URL with a set of routes.
+     *
+     * @param string $pathinfo The path info to be parsed
+     *
+     * @return array An array of parameters
+     *
+     * @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);
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/README.md b/3rdparty/symfony/routing/Symfony/Component/Routing/README.md
new file mode 100644 (file)
index 0000000..eb72334
--- /dev/null
@@ -0,0 +1,32 @@
+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:
+
+    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
+---------
+
+Unit tests:
+
+https://github.com/symfony/symfony/tree/master/tests/Symfony/Tests/Component/Routing
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/RequestContext.php b/3rdparty/symfony/routing/Symfony/Component/Routing/RequestContext.php
new file mode 100644 (file)
index 0000000..fef85b6
--- /dev/null
@@ -0,0 +1,250 @@
+<?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;
+
+/**
+ * Holds information about the current request.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @api
+ */
+class RequestContext
+{
+    private $baseUrl;
+    private $method;
+    private $host;
+    private $scheme;
+    private $httpPort;
+    private $httpsPort;
+    private $parameters;
+
+    /**
+     * Constructor.
+     *
+     * @param string  $baseUrl   The base URL
+     * @param string  $method    The HTTP method
+     * @param string  $host      The HTTP host name
+     * @param string  $scheme    The HTTP scheme
+     * @param integer $httpPort  The HTTP port
+     * @param integer $httpsPort The HTTPS port
+     *
+     * @api
+     */
+    public function __construct($baseUrl = '', $method = 'GET', $host = 'localhost', $scheme = 'http', $httpPort = 80, $httpsPort = 443)
+    {
+        $this->baseUrl = $baseUrl;
+        $this->method = strtoupper($method);
+        $this->host = $host;
+        $this->scheme = strtolower($scheme);
+        $this->httpPort = $httpPort;
+        $this->httpsPort = $httpsPort;
+        $this->parameters = array();
+    }
+
+    /**
+     * Gets the base URL.
+     *
+     * @return string The base URL
+     */
+    public function getBaseUrl()
+    {
+        return $this->baseUrl;
+    }
+
+    /**
+     * Sets the base URL.
+     *
+     * @param string $baseUrl The base URL
+     *
+     * @api
+     */
+    public function setBaseUrl($baseUrl)
+    {
+        $this->baseUrl = $baseUrl;
+    }
+
+    /**
+     * Gets the HTTP method.
+     *
+     * The method is always an uppercased string.
+     *
+     * @return string The HTTP method
+     */
+    public function getMethod()
+    {
+        return $this->method;
+    }
+
+    /**
+     * Sets the HTTP method.
+     *
+     * @param string $method The HTTP method
+     *
+     * @api
+     */
+    public function setMethod($method)
+    {
+        $this->method = strtoupper($method);
+    }
+
+    /**
+     * Gets the HTTP host.
+     *
+     * @return string The HTTP host
+     */
+    public function getHost()
+    {
+        return $this->host;
+    }
+
+    /**
+     * Sets the HTTP host.
+     *
+     * @param string $host The HTTP host
+     *
+     * @api
+     */
+    public function setHost($host)
+    {
+        $this->host = $host;
+    }
+
+    /**
+     * Gets the HTTP scheme.
+     *
+     * @return string The HTTP scheme
+     */
+    public function getScheme()
+    {
+        return $this->scheme;
+    }
+
+    /**
+     * Sets the HTTP scheme.
+     *
+     * @param string $scheme The HTTP scheme
+     *
+     * @api
+     */
+    public function setScheme($scheme)
+    {
+        $this->scheme = strtolower($scheme);
+    }
+
+    /**
+     * Gets the HTTP port.
+     *
+     * @return string The HTTP port
+     */
+    public function getHttpPort()
+    {
+        return $this->httpPort;
+    }
+
+    /**
+     * Sets the HTTP port.
+     *
+     * @param string $httpPort The HTTP port
+     *
+     * @api
+     */
+    public function setHttpPort($httpPort)
+    {
+        $this->httpPort = $httpPort;
+    }
+
+    /**
+     * Gets the HTTPS port.
+     *
+     * @return string The HTTPS port
+     */
+    public function getHttpsPort()
+    {
+        return $this->httpsPort;
+    }
+
+    /**
+     * Sets the HTTPS port.
+     *
+     * @param string $httpsPort The HTTPS port
+     *
+     * @api
+     */
+    public function setHttpsPort($httpsPort)
+    {
+        $this->httpsPort = $httpsPort;
+    }
+
+    /**
+     * Returns the parameters.
+     *
+     * @return array The parameters
+     */
+    public function getParameters()
+    {
+        return $this->parameters;
+    }
+
+    /**
+     * Sets the parameters.
+     *
+     * This method implements a fluent interface.
+     *
+     * @param array $parameters The parameters
+     *
+     * @return Route The current Route instance
+     */
+    public function setParameters(array $parameters)
+    {
+        $this->parameters = $parameters;
+
+        return $this;
+    }
+
+    /**
+     * Gets a parameter value.
+     *
+     * @param string $name A parameter name
+     *
+     * @return mixed The parameter value
+     */
+    public function getParameter($name)
+    {
+        return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
+    }
+
+    /**
+     * Checks if a parameter value is set for the given parameter.
+     *
+     * @param string $name A parameter name
+     *
+     * @return Boolean true if the parameter value is set, false otherwise
+     */
+    public function hasParameter($name)
+    {
+        return array_key_exists($name, $this->parameters);
+    }
+
+    /**
+     * Sets a parameter value.
+     *
+     * @param string $name      A parameter name
+     * @param mixed  $parameter The parameter value
+     *
+     * @api
+     */
+    public function setParameter($name, $parameter)
+    {
+        $this->parameters[$name] = $parameter;
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/RequestContextAwareInterface.php b/3rdparty/symfony/routing/Symfony/Component/Routing/RequestContextAwareInterface.php
new file mode 100644 (file)
index 0000000..38443a8
--- /dev/null
@@ -0,0 +1,27 @@
+<?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;
+
+/**
+ * @api
+ */
+interface RequestContextAwareInterface
+{
+    /**
+     * Sets the request context.
+     *
+     * @param RequestContext $context The context
+     *
+     * @api
+     */
+    public function setContext(RequestContext $context);
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Route.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Route.php
new file mode 100644 (file)
index 0000000..5485683
--- /dev/null
@@ -0,0 +1,312 @@
+<?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;
+
+/**
+ * A Route describes a route and its parameters.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @api
+ */
+class Route
+{
+    private $pattern;
+    private $defaults;
+    private $requirements;
+    private $options;
+    private $compiled;
+
+    private static $compilers = array();
+
+    /**
+     * Constructor.
+     *
+     * Available options:
+     *
+     *  * compiler_class: A class name able to compile this route instance (RouteCompiler by default)
+     *
+     * @param string $pattern      The 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
+     *
+     * @api
+     */
+    public function __construct($pattern, array $defaults = array(), array $requirements = array(), array $options = array())
+    {
+        $this->setPattern($pattern);
+        $this->setDefaults($defaults);
+        $this->setRequirements($requirements);
+        $this->setOptions($options);
+    }
+
+    public function __clone()
+    {
+        $this->compiled = null;
+    }
+
+    /**
+     * Returns the pattern.
+     *
+     * @return string The pattern
+     */
+    public function getPattern()
+    {
+        return $this->pattern;
+    }
+
+    /**
+     * Sets the pattern.
+     *
+     * This method implements a fluent interface.
+     *
+     * @param string $pattern The pattern
+     *
+     * @return Route The current Route instance
+     */
+    public function setPattern($pattern)
+    {
+        $this->pattern = trim($pattern);
+
+        // a route must start with a slash
+        if (empty($this->pattern) || '/' !== $this->pattern[0]) {
+            $this->pattern = '/'.$this->pattern;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Returns the options.
+     *
+     * @return array The options
+     */
+    public function getOptions()
+    {
+        return $this->options;
+    }
+
+    /**
+     * Sets the options.
+     *
+     * This method implements a fluent interface.
+     *
+     * @param array $options The options
+     *
+     * @return Route The current Route instance
+     */
+    public function setOptions(array $options)
+    {
+        $this->options = array_merge(array(
+            'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler',
+        ), $options);
+
+        return $this;
+    }
+
+    /**
+     * Sets an option value.
+     *
+     * This method implements a fluent interface.
+     *
+     * @param string $name  An option name
+     * @param mixed  $value The option value
+     *
+     * @return Route The current Route instance
+     *
+     * @api
+     */
+    public function setOption($name, $value)
+    {
+        $this->options[$name] = $value;
+
+        return $this;
+    }
+
+    /**
+     * Get an option value.
+     *
+     * @param string $name An option name
+     *
+     * @return mixed The option value
+     */
+    public function getOption($name)
+    {
+        return isset($this->options[$name]) ? $this->options[$name] : null;
+    }
+
+    /**
+     * Returns the defaults.
+     *
+     * @return array The defaults
+     */
+    public function getDefaults()
+    {
+        return $this->defaults;
+    }
+
+    /**
+     * Sets the defaults.
+     *
+     * This method implements a fluent interface.
+     *
+     * @param array $defaults The defaults
+     *
+     * @return Route The current Route instance
+     */
+    public function setDefaults(array $defaults)
+    {
+        $this->defaults = array();
+        foreach ($defaults as $name => $default) {
+            $this->defaults[(string) $name] = $default;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Gets a default value.
+     *
+     * @param string $name A variable name
+     *
+     * @return mixed The default value
+     */
+    public function getDefault($name)
+    {
+        return isset($this->defaults[$name]) ? $this->defaults[$name] : null;
+    }
+
+    /**
+     * Checks if a default value is set for the given variable.
+     *
+     * @param string $name A variable name
+     *
+     * @return Boolean true if the default value is set, false otherwise
+     */
+    public function hasDefault($name)
+    {
+        return array_key_exists($name, $this->defaults);
+    }
+
+    /**
+     * Sets a default value.
+     *
+     * @param string $name    A variable name
+     * @param mixed  $default The default value
+     *
+     * @return Route The current Route instance
+     *
+     * @api
+     */
+    public function setDefault($name, $default)
+    {
+        $this->defaults[(string) $name] = $default;
+
+        return $this;
+    }
+
+    /**
+     * Returns the requirements.
+     *
+     * @return array The requirements
+     */
+    public function getRequirements()
+    {
+        return $this->requirements;
+    }
+
+    /**
+     * Sets the requirements.
+     *
+     * This method implements a fluent interface.
+     *
+     * @param array $requirements The requirements
+     *
+     * @return Route The current Route instance
+     */
+    public function setRequirements(array $requirements)
+    {
+        $this->requirements = array();
+        foreach ($requirements as $key => $regex) {
+            $this->requirements[$key] = $this->sanitizeRequirement($key, $regex);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Returns the requirement for the given key.
+     *
+     * @param string $key The key
+     *
+     * @return string The regex
+     */
+    public function getRequirement($key)
+    {
+        return isset($this->requirements[$key]) ? $this->requirements[$key] : null;
+    }
+
+    /**
+     * Sets a requirement for the given key.
+     *
+     * @param string $key   The key
+     * @param string $regex The regex
+     *
+     * @return Route The current Route instance
+     *
+     * @api
+     */
+    public function setRequirement($key, $regex)
+    {
+        $this->requirements[$key] = $this->sanitizeRequirement($key, $regex);
+
+        return $this;
+    }
+
+    /**
+     * Compiles the route.
+     *
+     * @return CompiledRoute A CompiledRoute instance
+     */
+    public function compile()
+    {
+        if (null !== $this->compiled) {
+            return $this->compiled;
+        }
+
+        $class = $this->getOption('compiler_class');
+
+        if (!isset(self::$compilers[$class])) {
+            self::$compilers[$class] = new $class;
+        }
+
+        return $this->compiled = self::$compilers[$class]->compile($this);
+    }
+
+    private function sanitizeRequirement($key, $regex)
+    {
+        if (is_array($regex)) {
+            throw new \InvalidArgumentException(sprintf('Routing requirements must be a string, array given for "%s"', $key));
+        }
+
+        if ('^' == $regex[0]) {
+            $regex = substr($regex, 1);
+        }
+
+        if ('$' == substr($regex, -1)) {
+            $regex = substr($regex, 0, -1);
+        }
+
+        return $regex;
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/RouteCollection.php b/3rdparty/symfony/routing/Symfony/Component/Routing/RouteCollection.php
new file mode 100644 (file)
index 0000000..b3289d3
--- /dev/null
@@ -0,0 +1,259 @@
+<?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\Resource\ResourceInterface;
+
+/**
+ * A RouteCollection represents a set of Route instances.
+ *
+ * When adding a route, it overrides existing routes with the
+ * same name defined in the instance or its children and parents.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @api
+ */
+class RouteCollection implements \IteratorAggregate
+{
+    private $routes;
+    private $resources;
+    private $prefix;
+    private $parent;
+
+    /**
+     * Constructor.
+     *
+     * @api
+     */
+    public function __construct()
+    {
+        $this->routes = array();
+        $this->resources = array();
+        $this->prefix = '';
+    }
+
+    public function __clone()
+    {
+        foreach ($this->routes as $name => $route) {
+            $this->routes[$name] = clone $route;
+            if ($route instanceof RouteCollection) {
+                $this->routes[$name]->setParent($this);
+            }
+        }
+    }
+
+    /**
+     * Gets the parent RouteCollection.
+     *
+     * @return RouteCollection The parent RouteCollection
+     */
+    public function getParent()
+    {
+        return $this->parent;
+    }
+
+    /**
+     * Sets the parent RouteCollection.
+     *
+     * @param RouteCollection $parent The parent RouteCollection
+     */
+    public function setParent(RouteCollection $parent)
+    {
+        $this->parent = $parent;
+    }
+
+    /**
+     * Gets the current RouteCollection as an Iterator.
+     *
+     * @return \ArrayIterator An \ArrayIterator interface
+     */
+    public function getIterator()
+    {
+        return new \ArrayIterator($this->routes);
+    }
+
+    /**
+     * Adds a route.
+     *
+     * @param string $name  The route name
+     * @param Route  $route A Route instance
+     *
+     * @throws \InvalidArgumentException When route name contains non valid characters
+     *
+     * @api
+     */
+    public function add($name, Route $route)
+    {
+        if (!preg_match('/^[a-z0-9A-Z_.]+$/', $name)) {
+            throw new \InvalidArgumentException(sprintf('The provided route name "%s" contains non valid characters. A route name must only contain digits (0-9), letters (a-z and A-Z), underscores (_) and dots (.).', $name));
+        }
+
+        $parent = $this;
+        while ($parent->getParent()) {
+            $parent = $parent->getParent();
+        }
+
+        if ($parent) {
+            $parent->remove($name);
+        }
+
+        $this->routes[$name] = $route;
+    }
+
+    /**
+     * Returns the array of routes.
+     *
+     * @return array An array of routes
+     */
+    public function all()
+    {
+        $routes = array();
+        foreach ($this->routes as $name => $route) {
+            if ($route instanceof RouteCollection) {
+                $routes = array_merge($routes, $route->all());
+            } else {
+                $routes[$name] = $route;
+            }
+        }
+
+        return $routes;
+    }
+
+    /**
+     * Gets a route by name.
+     *
+     * @param string $name The route name
+     *
+     * @return Route  $route A Route instance
+     */
+    public function get($name)
+    {
+        // get the latest defined route
+        foreach (array_reverse($this->routes) as $routes) {
+            if (!$routes instanceof RouteCollection) {
+                continue;
+            }
+
+            if (null !== $route = $routes->get($name)) {
+                return $route;
+            }
+        }
+
+        if (isset($this->routes[$name])) {
+            return $this->routes[$name];
+        }
+    }
+
+    /**
+     * Removes a route by name.
+     *
+     * @param string $name The route name
+     */
+    public function remove($name)
+    {
+        if (isset($this->routes[$name])) {
+            unset($this->routes[$name]);
+        }
+
+        foreach ($this->routes as $routes) {
+            if ($routes instanceof RouteCollection) {
+                $routes->remove($name);
+            }
+        }
+    }
+
+    /**
+     * Adds a route collection to the current set of routes (at the end of the current set).
+     *
+     * @param RouteCollection $collection A RouteCollection instance
+     * @param string          $prefix     An optional prefix to add before each pattern of the route collection
+     *
+     * @api
+     */
+    public function addCollection(RouteCollection $collection, $prefix = '')
+    {
+        $collection->setParent($this);
+        $collection->addPrefix($prefix);
+
+        // remove all routes with the same name in all existing collections
+        foreach (array_keys($collection->all()) as $name) {
+            $this->remove($name);
+        }
+
+        $this->routes[] = $collection;
+    }
+
+    /**
+     * Adds a prefix to all routes in the current set.
+     *
+     * @param string $prefix An optional prefix to add before each pattern of the route collection
+     *
+     * @api
+     */
+    public function addPrefix($prefix)
+    {
+        // a prefix must not end with a slash
+        $prefix = rtrim($prefix, '/');
+
+        if (!$prefix) {
+            return;
+        }
+
+        // a prefix must start with a slash
+        if ('/' !== $prefix[0]) {
+            $prefix = '/'.$prefix;
+        }
+
+        $this->prefix = $prefix.$this->prefix;
+
+        foreach ($this->routes as $name => $route) {
+            if ($route instanceof RouteCollection) {
+                $route->addPrefix($prefix);
+            } else {
+                $route->setPattern($prefix.$route->getPattern());
+            }
+        }
+    }
+
+    public function getPrefix()
+    {
+        return $this->prefix;
+    }
+
+    /**
+     * Returns an array of resources loaded to build this collection.
+     *
+     * @return ResourceInterface[] An array of resources
+     */
+    public function getResources()
+    {
+        $resources = $this->resources;
+        foreach ($this as $routes) {
+            if ($routes instanceof RouteCollection) {
+                $resources = array_merge($resources, $routes->getResources());
+            }
+        }
+
+        return array_unique($resources);
+    }
+
+    /**
+     * Adds a resource for this collection.
+     *
+     * @param ResourceInterface $resource A resource instance
+     */
+    public function addResource(ResourceInterface $resource)
+    {
+        $this->resources[] = $resource;
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/RouteCompiler.php b/3rdparty/symfony/routing/Symfony/Component/Routing/RouteCompiler.php
new file mode 100644 (file)
index 0000000..72ececc
--- /dev/null
@@ -0,0 +1,128 @@
+<?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;
+
+/**
+ * RouteCompiler compiles Route instances to CompiledRoute instances.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class RouteCompiler implements RouteCompilerInterface
+{
+    /**
+     * Compiles the current route instance.
+     *
+     * @param Route $route A Route instance
+     *
+     * @return CompiledRoute A CompiledRoute instance
+     */
+    public function compile(Route $route)
+    {
+        $pattern = $route->getPattern();
+        $len = strlen($pattern);
+        $tokens = array();
+        $variables = array();
+        $pos = 0;
+        preg_match_all('#.\{([\w\d_]+)\}#', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
+        foreach ($matches as $match) {
+            if ($text = substr($pattern, $pos, $match[0][1] - $pos)) {
+                $tokens[] = array('text', $text);
+            }
+            $seps = array($pattern[$pos]);
+            $pos = $match[0][1] + strlen($match[0][0]);
+            $var = $match[1][0];
+
+            if ($req = $route->getRequirement($var)) {
+                $regexp = $req;
+            } else {
+                if ($pos !== $len) {
+                    $seps[] = $pattern[$pos];
+                }
+                $regexp = sprintf('[^%s]+?', preg_quote(implode('', array_unique($seps)), '#'));
+            }
+
+            $tokens[] = array('variable', $match[0][0][0], $regexp, $var);
+
+            if (in_array($var, $variables)) {
+                throw new \LogicException(sprintf('Route pattern "%s" cannot reference variable name "%s" more than once.', $route->getPattern(), $var));
+            }
+
+            $variables[] = $var;
+        }
+
+        if ($pos < $len) {
+            $tokens[] = array('text', substr($pattern, $pos));
+        }
+
+        // find the first optional token
+        $firstOptional = INF;
+        for ($i = count($tokens) - 1; $i >= 0; $i--) {
+            $token = $tokens[$i];
+            if ('variable' === $token[0] && $route->hasDefault($token[3])) {
+                $firstOptional = $i;
+            } else {
+                break;
+            }
+        }
+
+        // compute the matching regexp
+        $regexp = '';
+        for ($i = 0, $nbToken = count($tokens); $i < $nbToken; $i++) {
+            $regexp .= $this->computeRegexp($tokens, $i, $firstOptional);
+        }
+
+        return new CompiledRoute(
+            $route,
+            'text' === $tokens[0][0] ? $tokens[0][1] : '',
+            sprintf("#^%s$#s", $regexp),
+            array_reverse($tokens),
+            $variables
+        );
+    }
+
+    /**
+     * Computes the regexp used to match the token.
+     *
+     * @param array   $tokens        The route tokens
+     * @param integer $index         The index of the current token
+     * @param integer $firstOptional The index of the first optional token
+     *
+     * @return string The regexp
+     */
+    private function computeRegexp(array $tokens, $index, $firstOptional)
+    {
+        $token = $tokens[$index];
+        if ('text' === $token[0]) {
+            // Text tokens
+            return preg_quote($token[1], '#');
+        } else {
+            // Variable tokens
+            if (0 === $index && 0 === $firstOptional && 1 == count($tokens)) {
+                // When the only token is an optional variable token, the separator is required
+                return sprintf('%s(?P<%s>%s)?', preg_quote($token[1], '#'), $token[3], $token[2]);
+            } else {
+                $nbTokens = count($tokens);
+                $regexp = sprintf('%s(?P<%s>%s)', preg_quote($token[1], '#'), $token[3], $token[2]);
+                if ($index >= $firstOptional) {
+                    // Enclose each optional tokens in a subpattern to make it optional
+                    $regexp = "(?:$regexp";
+                    if ($nbTokens - 1 == $index) {
+                        // Close the optional subpatterns
+                        $regexp .= str_repeat(")?", $nbTokens - $firstOptional);
+                    }
+                }
+
+                return $regexp;
+            }
+        }
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/RouteCompilerInterface.php b/3rdparty/symfony/routing/Symfony/Component/Routing/RouteCompilerInterface.php
new file mode 100644 (file)
index 0000000..5c988ad
--- /dev/null
@@ -0,0 +1,29 @@
+<?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;
+
+/**
+ * RouteCompilerInterface is the interface that all RouteCompiler classes must implements.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+interface RouteCompilerInterface
+{
+    /**
+     * Compiles the current route instance.
+     *
+     * @param Route $route A Route instance
+     *
+     * @return CompiledRoute A CompiledRoute instance
+     */
+    public function compile(Route $route);
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/Router.php b/3rdparty/symfony/routing/Symfony/Component/Routing/Router.php
new file mode 100644 (file)
index 0000000..eadb223
--- /dev/null
@@ -0,0 +1,263 @@
+<?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\Loader\LoaderInterface;
+use Symfony\Component\Config\ConfigCache;
+
+/**
+ * The Router class is an example of the integration of all pieces of the
+ * routing system for easier use.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class Router implements RouterInterface
+{
+    protected $matcher;
+    protected $generator;
+    protected $defaults;
+    protected $context;
+    protected $loader;
+    protected $collection;
+    protected $resource;
+    protected $options;
+
+    /**
+     * Constructor.
+     *
+     * @param LoaderInterface $loader   A LoaderInterface instance
+     * @param mixed           $resource The main resource to load
+     * @param array           $options  An array of options
+     * @param RequestContext  $context  The context
+     * @param array           $defaults The default values
+     */
+    public function __construct(LoaderInterface $loader, $resource, array $options = array(), RequestContext $context = null, array $defaults = array())
+    {
+        $this->loader = $loader;
+        $this->resource = $resource;
+        $this->context = null === $context ? new RequestContext() : $context;
+        $this->defaults = $defaults;
+        $this->setOptions($options);
+    }
+
+    /**
+     * Sets options.
+     *
+     * Available options:
+     *
+     *   * cache_dir:     The cache directory (or null to disable caching)
+     *   * debug:         Whether to enable debugging or not (false by default)
+     *   * resource_type: Type hint for the main resource (optional)
+     *
+     * @param array $options An array of options
+     *
+     * @throws \InvalidArgumentException When unsupported option is provided
+     */
+    public function setOptions(array $options)
+    {
+        $this->options = array(
+            'cache_dir'              => null,
+            'debug'                  => false,
+            'generator_class'        => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
+            'generator_base_class'   => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
+            'generator_dumper_class' => 'Symfony\\Component\\Routing\\Generator\\Dumper\\PhpGeneratorDumper',
+            'generator_cache_class'  => 'ProjectUrlGenerator',
+            'matcher_class'          => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
+            'matcher_base_class'     => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
+            'matcher_dumper_class'   => 'Symfony\\Component\\Routing\\Matcher\\Dumper\\PhpMatcherDumper',
+            'matcher_cache_class'    => 'ProjectUrlMatcher',
+            'resource_type'          => null,
+        );
+
+        // check option names and live merge, if errors are encountered Exception will be thrown
+        $invalid = array();
+        $isInvalid = false;
+        foreach ($options as $key => $value) {
+            if (array_key_exists($key, $this->options)) {
+                $this->options[$key] = $value;
+            } else {
+                $isInvalid = true;
+                $invalid[] = $key;
+            }
+        }
+
+        if ($isInvalid) {
+            throw new \InvalidArgumentException(sprintf('The Router does not support the following options: "%s".', implode('\', \'', $invalid)));
+        }
+    }
+
+    /**
+     * Sets an option.
+     *
+     * @param string $key   The key
+     * @param mixed  $value The value
+     *
+     * @throws \InvalidArgumentException
+     */
+    public function setOption($key, $value)
+    {
+        if (!array_key_exists($key, $this->options)) {
+            throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key));
+        }
+
+        $this->options[$key] = $value;
+    }
+
+    /**
+     * Gets an option value.
+     *
+     * @param string $key The key
+     *
+     * @return mixed The value
+     *
+     * @throws \InvalidArgumentException
+     */
+    public function getOption($key)
+    {
+        if (!array_key_exists($key, $this->options)) {
+            throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key));
+        }
+
+        return $this->options[$key];
+    }
+
+    /**
+     * Gets the RouteCollection instance associated with this Router.
+     *
+     * @return RouteCollection A RouteCollection instance
+     */
+    public function getRouteCollection()
+    {
+        if (null === $this->collection) {
+            $this->collection = $this->loader->load($this->resource, $this->options['resource_type']);
+        }
+
+        return $this->collection;
+    }
+
+    /**
+     * Sets the request context.
+     *
+     * @param RequestContext $context The context
+     */
+    public function setContext(RequestContext $context)
+    {
+        $this->context = $context;
+
+        $this->getMatcher()->setContext($context);
+        $this->getGenerator()->setContext($context);
+    }
+
+    /**
+     * Gets the request context.
+     *
+     * @return RequestContext The context
+     */
+    public function getContext()
+    {
+        return $this->context;
+    }
+
+    /**
+     * Generates a URL from the given parameters.
+     *
+     * @param string  $name       The name of the route
+     * @param mixed   $parameters An array of parameters
+     * @param Boolean $absolute   Whether to generate an absolute URL
+     *
+     * @return string The generated URL
+     */
+    public function generate($name, $parameters = array(), $absolute = false)
+    {
+        return $this->getGenerator()->generate($name, $parameters, $absolute);
+    }
+
+    /**
+     * Tries to match a URL with a set of routes.
+     *
+     * Returns false if no route matches the URL.
+     *
+     * @param string $url URL to be parsed
+     *
+     * @return array|false An array of parameters or false if no route matches
+     */
+    public function match($url)
+    {
+        return $this->getMatcher()->match($url);
+    }
+
+    /**
+     * Gets the UrlMatcher instance associated with this Router.
+     *
+     * @return UrlMatcherInterface A UrlMatcherInterface instance
+     */
+    public function getMatcher()
+    {
+        if (null !== $this->matcher) {
+            return $this->matcher;
+        }
+
+        if (null === $this->options['cache_dir'] || null === $this->options['matcher_cache_class']) {
+            return $this->matcher = new $this->options['matcher_class']($this->getRouteCollection(), $this->context, $this->defaults);
+        }
+
+        $class = $this->options['matcher_cache_class'];
+        $cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']);
+        if (!$cache->isFresh($class)) {
+            $dumper = new $this->options['matcher_dumper_class']($this->getRouteCollection());
+
+            $options = array(
+                'class'      => $class,
+                'base_class' => $this->options['matcher_base_class'],
+            );
+
+            $cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
+        }
+
+        require_once $cache;
+
+        return $this->matcher = new $class($this->context, $this->defaults);
+    }
+
+    /**
+     * Gets the UrlGenerator instance associated with this Router.
+     *
+     * @return UrlGeneratorInterface A UrlGeneratorInterface instance
+     */
+    public function getGenerator()
+    {
+        if (null !== $this->generator) {
+            return $this->generator;
+        }
+
+        if (null === $this->options['cache_dir'] || null === $this->options['generator_cache_class']) {
+            return $this->generator = new $this->options['generator_class']($this->getRouteCollection(), $this->context, $this->defaults);
+        }
+
+        $class = $this->options['generator_cache_class'];
+        $cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']);
+        if (!$cache->isFresh($class)) {
+            $dumper = new $this->options['generator_dumper_class']($this->getRouteCollection());
+
+            $options = array(
+                'class'      => $class,
+                'base_class' => $this->options['generator_base_class'],
+            );
+
+            $cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
+        }
+
+        require_once $cache;
+
+        return $this->generator = new $class($this->context, $this->defaults);
+    }
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/RouterInterface.php b/3rdparty/symfony/routing/Symfony/Component/Routing/RouterInterface.php
new file mode 100644 (file)
index 0000000..961342b
--- /dev/null
@@ -0,0 +1,26 @@
+<?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\Routing\Generator\UrlGeneratorInterface;
+use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
+
+/**
+ * RouterInterface is the interface that all Router classes must implements.
+ *
+ * This interface is the concatenation of UrlMatcherInterface and UrlGeneratorInterface.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+interface RouterInterface extends UrlMatcherInterface, UrlGeneratorInterface
+{
+}
diff --git a/3rdparty/symfony/routing/Symfony/Component/Routing/composer.json b/3rdparty/symfony/routing/Symfony/Component/Routing/composer.json
new file mode 100644 (file)
index 0000000..8d29398
--- /dev/null
@@ -0,0 +1,29 @@
+{
+    "name": "symfony/routing",
+    "type": "library",
+    "description": "Symfony Routing Component",
+    "keywords": [],
+    "homepage": "http://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Fabien Potencier",
+            "email": "fabien@symfony.com"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "http://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=5.3.2"
+    },
+    "suggest": {
+        "symfony/config": "self.version",
+        "symfony/yaml": "self.version"
+    },
+    "autoload": {
+        "psr-0": { "Symfony\\Component\\Routing": "" }
+    },
+    "target-dir": "Symfony/Component/Routing"
+}
diff --git a/composer.json b/composer.json
deleted file mode 100644 (file)
index 7916b15..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-       "description": "ownCloud gives you universal access to your files/contacts/calendar through a web interface or WebDAV.",
-       "homepage": "http://owncloud.org",
-       "license": "AGPL-3.0+",
-       "support": {
-               "email": "owncloud@kde.org",
-               "irc": "irc://irc.freenode.org/owncloud",
-               "forum": "http://forum.owncloud.org/",
-               "issues": "https://github.com/owncloud/core/issues"
-       },
-       "require": {
-               "php": ">=5.3.2",
-               "symfony/routing": "2.0.*"
-       },
-       "config": {
-               "vendor-dir": "3rdparty"
-       }
-}