Update to Drupal 8.1.0. For more information, see https://www.drupal.org/drupal-8.1.0-release-notes

This commit is contained in:
Pantheon Automation 2016-04-20 09:56:34 -07:00 committed by Greg Anderson
parent b11a755ba8
commit c0a0d5a94c
6920 changed files with 64395 additions and 57312 deletions

View file

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

View file

@ -53,7 +53,7 @@ use Psr\Log\LoggerInterface;
*/
class {$options['class']} extends {$options['base_class']}
{
private static \$declaredRoutes = {$this->generateDeclaredRoutes()};
private static \$declaredRoutes;
/**
* Constructor.
@ -62,6 +62,9 @@ class {$options['class']} extends {$options['base_class']}
{
\$this->context = \$context;
\$this->logger = \$logger;
if (null === self::\$declaredRoutes) {
self::\$declaredRoutes = {$this->generateDeclaredRoutes()};
}
}
{$this->generateGenerateMethod()}
@ -104,16 +107,16 @@ EOF;
*/
private function generateGenerateMethod()
{
return <<<EOF
public function generate(\$name, \$parameters = array(), \$referenceType = self::ABSOLUTE_PATH)
return <<<'EOF'
public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
{
if (!isset(self::\$declaredRoutes[\$name])) {
throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', \$name));
if (!isset(self::$declaredRoutes[$name])) {
throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name));
}
list(\$variables, \$defaults, \$requirements, \$tokens, \$hostTokens, \$requiredSchemes) = self::\$declaredRoutes[\$name];
list($variables, $defaults, $requirements, $tokens, $hostTokens, $requiredSchemes) = self::$declaredRoutes[$name];
return \$this->doGenerate(\$variables, \$defaults, \$requirements, \$tokens, \$parameters, \$name, \$referenceType, \$hostTokens, \$requiredSchemes);
return $this->doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens, $requiredSchemes);
}
EOF;
}

View file

@ -143,6 +143,20 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt
*/
protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens, array $requiredSchemes = array())
{
if (is_bool($referenceType) || is_string($referenceType)) {
@trigger_error('The hardcoded value you are using for the $referenceType argument of the '.__CLASS__.'::generate method is deprecated since version 2.8 and will not be supported anymore in 3.0. Use the constants defined in the UrlGeneratorInterface instead.', E_USER_DEPRECATED);
if (true === $referenceType) {
$referenceType = self::ABSOLUTE_URL;
} elseif (false === $referenceType) {
$referenceType = self::ABSOLUTE_PATH;
} elseif ('relative' === $referenceType) {
$referenceType = self::RELATIVE_PATH;
} elseif ('network' === $referenceType) {
$referenceType = self::NETWORK_PATH;
}
}
$variables = array_flip($variables);
$mergedParams = array_replace($defaults, $this->context->getParameters(), $parameters);
@ -202,16 +216,7 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt
$scheme = $this->context->getScheme();
if ($requiredSchemes) {
$schemeMatched = false;
foreach ($requiredSchemes as $requiredScheme) {
if ($scheme === $requiredScheme) {
$schemeMatched = true;
break;
}
}
if (!$schemeMatched) {
if (!in_array($scheme, $requiredSchemes, true)) {
$referenceType = self::ABSOLUTE_URL;
$scheme = current($requiredSchemes);
}

View file

@ -34,25 +34,25 @@ interface UrlGeneratorInterface extends RequestContextAwareInterface
/**
* Generates an absolute URL, e.g. "http://example.com/dir/file".
*/
const ABSOLUTE_URL = true;
const ABSOLUTE_URL = 0;
/**
* Generates an absolute path, e.g. "/dir/file".
*/
const ABSOLUTE_PATH = false;
const ABSOLUTE_PATH = 1;
/**
* Generates a relative path based on the current request path, e.g. "../parent-file".
*
* @see UrlGenerator::getRelativePath()
*/
const RELATIVE_PATH = 'relative';
const RELATIVE_PATH = 2;
/**
* Generates a network path, e.g. "//example.com/dir/file".
* Such reference reuses the current scheme but specifies the host.
*/
const NETWORK_PATH = 'network';
const NETWORK_PATH = 3;
/**
* Generates a URL or path for a specific route based on the given parameters.
@ -69,9 +69,9 @@ interface UrlGeneratorInterface extends RequestContextAwareInterface
*
* If there is no route with the given name, the generator must throw the RouteNotFoundException.
*
* @param string $name The name of the route
* @param mixed $parameters An array of parameters
* @param bool|string $referenceType The type of reference to be generated (one of the constants)
* @param string $name The name of the route
* @param mixed $parameters An array of parameters
* @param int $referenceType The type of reference to be generated (one of the constants)
*
* @return string The generated URL
*

View file

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

View file

@ -110,7 +110,7 @@ abstract class AnnotationClassLoader implements LoaderInterface
$class = new \ReflectionClass($class);
if ($class->isAbstract()) {
throw new \InvalidArgumentException(sprintf('Annotations from class "%s" cannot be read as it is abstract.', $class));
throw new \InvalidArgumentException(sprintf('Annotations from class "%s" cannot be read as it is abstract.', $class->getName()));
}
$globals = $this->getGlobals($class);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -11,6 +11,7 @@
namespace Symfony\Component\Routing\Matcher;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Exception\ExceptionInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
@ -40,6 +41,15 @@ class TraceableUrlMatcher extends UrlMatcher
return $this->traces;
}
public function getTracesForRequest(Request $request)
{
$this->request = $request;
$traces = $this->getTraces($request->getPathInfo());
$this->request = null;
return $traces;
}
protected function matchCollection($pathinfo, RouteCollection $routes)
{
foreach ($routes as $name => $route) {

View file

@ -1,36 +1,13 @@
Routing Component
=================
Routing associates a request with the code that will convert it to a response.
The example below demonstrates how you can set up a fully working routing
system:
```php
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
$routes = new RouteCollection();
$routes->add('hello', new Route('/hello', array('controller' => 'foo')));
$context = new RequestContext();
// this is optional and can be done without a Request instance
$context->fromRequest(Request::createFromGlobals());
$matcher = new UrlMatcher($routes, $context);
$parameters = $matcher->match('/hello');
```
The Routing component maps an HTTP request to a set of configuration variables.
Resources
---------
You can run the unit tests with the following command:
$ cd path/to/Symfony/Component/Routing/
$ composer install
$ phpunit
* [Documentation](https://symfony.com/doc/current/components/routing/index.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)

View file

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

View file

@ -19,10 +19,10 @@
"php": ">=5.3.9"
},
"require-dev": {
"symfony/config": "~2.7",
"symfony/http-foundation": "~2.3",
"symfony/yaml": "~2.0,>=2.0.5",
"symfony/expression-language": "~2.4",
"symfony/config": "~2.7|~3.0.0",
"symfony/http-foundation": "~2.3|~3.0.0",
"symfony/yaml": "~2.0,>=2.0.5|~3.0.0",
"symfony/expression-language": "~2.4|~3.0.0",
"doctrine/annotations": "~1.0",
"doctrine/common": "~2.2",
"psr/log": "~1.0"
@ -31,18 +31,23 @@
"symfony/config": "<2.7"
},
"suggest": {
"symfony/http-foundation": "For using a Symfony Request object",
"symfony/config": "For using the all-in-one router or any loader",
"symfony/yaml": "For using the YAML loader",
"symfony/expression-language": "For using expression matching",
"doctrine/annotations": "For using the annotation loader"
"doctrine/annotations": "For using the annotation loader",
"symfony/dependency-injection": "For loading routes from a service"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Routing\\": "" }
"psr-4": { "Symfony\\Component\\Routing\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "2.7-dev"
"dev-master": "2.8-dev"
}
}
}

View file

@ -20,8 +20,8 @@
<whitelist>
<directory>./</directory>
<exclude>
<directory>./vendor</directory>
<directory>./Tests</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>