Updates to vendors etc

This commit is contained in:
Chris Hunt
2025-07-11 15:57:48 +01:00
parent d972cbcd0a
commit 8fb6438254
8043 changed files with 248005 additions and 189479 deletions

View File

@@ -1,25 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Routing\Loader;
trigger_deprecation('symfony/routing', '6.4', 'The "%s" class is deprecated, use "%s" instead.', AnnotationClassLoader::class, AttributeClassLoader::class);
class_exists(AttributeClassLoader::class);
if (false) {
/**
* @deprecated since Symfony 6.4, to be removed in 7.0, use {@link AttributeClassLoader} instead
*/
abstract class AnnotationClassLoader extends AttributeClassLoader
{
}
}

View File

@@ -1,25 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Routing\Loader;
trigger_deprecation('symfony/routing', '6.4', 'The "%s" class is deprecated, use "%s" instead.', AnnotationDirectoryLoader::class, AttributeDirectoryLoader::class);
class_exists(AttributeDirectoryLoader::class);
if (false) {
/**
* @deprecated since Symfony 6.4, to be removed in 7.0, use {@link AttributeDirectoryLoader} instead
*/
class AnnotationDirectoryLoader extends AttributeDirectoryLoader
{
}
}

View File

@@ -1,25 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Routing\Loader;
trigger_deprecation('symfony/routing', '6.4', 'The "%s" class is deprecated, use "%s" instead.', AnnotationFileLoader::class, AttributeFileLoader::class);
class_exists(AttributeFileLoader::class);
if (false) {
/**
* @deprecated since Symfony 6.4, to be removed in 7.0, use {@link AttributeFileLoader} instead
*/
class AnnotationFileLoader extends AttributeFileLoader
{
}
}

View File

@@ -11,11 +11,13 @@
namespace Symfony\Component\Routing\Loader;
use Doctrine\Common\Annotations\Reader;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Config\Loader\LoaderResolverInterface;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Routing\Attribute\Route as RouteAnnotation;
use Symfony\Component\Routing\Attribute\DeprecatedAlias;
use Symfony\Component\Routing\Attribute\Route as RouteAttribute;
use Symfony\Component\Routing\Exception\InvalidArgumentException;
use Symfony\Component\Routing\Exception\LogicException;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
@@ -54,58 +56,36 @@ use Symfony\Component\Routing\RouteCollection;
abstract class AttributeClassLoader implements LoaderInterface
{
/**
* @var Reader|null
*
* @deprecated in Symfony 6.4, this property will be removed in Symfony 7.
* @deprecated since Symfony 7.2, use "setRouteAttributeClass()" instead.
*/
protected $reader;
protected string $routeAnnotationClass = RouteAttribute::class;
private string $routeAttributeClass = RouteAttribute::class;
protected int $defaultRouteIndex = 0;
/**
* @var string|null
*/
protected $env;
/**
* @var string
*/
protected $routeAnnotationClass = RouteAnnotation::class;
/**
* @var int
*/
protected $defaultRouteIndex = 0;
private bool $hasDeprecatedAnnotations = false;
/**
* @param string|null $env
*/
public function __construct($env = null)
{
if ($env instanceof Reader || null === $env && \func_num_args() > 1 && null !== func_get_arg(1)) {
trigger_deprecation('symfony/routing', '6.4', 'Passing an instance of "%s" as first and the environment as second argument to "%s" is deprecated. Pass the environment as first argument instead.', Reader::class, __METHOD__);
$this->reader = $env;
$env = \func_num_args() > 1 ? func_get_arg(1) : null;
}
if (\is_string($env) || null === $env) {
$this->env = $env;
} elseif ($env instanceof \Stringable || \is_scalar($env)) {
$this->env = (string) $env;
} else {
throw new \TypeError(__METHOD__.sprintf(': Parameter $env was expected to be a string or null, "%s" given.', get_debug_type($env)));
}
public function __construct(
protected readonly ?string $env = null,
) {
}
/**
* Sets the annotation class to read route properties from.
* @deprecated since Symfony 7.2, use "setRouteAttributeClass(string $class)" instead
*
* @return void
* Sets the annotation class to read route properties from.
*/
public function setRouteAnnotationClass(string $class)
public function setRouteAnnotationClass(string $class): void
{
trigger_deprecation('symfony/routing', '7.2', 'The "%s()" method is deprecated, use "%s::setRouteAttributeClass()" instead.', __METHOD__, self::class);
$this->setRouteAttributeClass($class);
}
/**
* Sets the attribute class to read route properties from.
*/
public function setRouteAttributeClass(string $class): void
{
$this->routeAnnotationClass = $class;
$this->routeAttributeClass = $class;
}
/**
@@ -114,102 +94,99 @@ abstract class AttributeClassLoader implements LoaderInterface
public function load(mixed $class, ?string $type = null): RouteCollection
{
if (!class_exists($class)) {
throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
throw new \InvalidArgumentException(\sprintf('Class "%s" does not exist.', $class));
}
$class = new \ReflectionClass($class);
if ($class->isAbstract()) {
throw new \InvalidArgumentException(sprintf('Attributes from class "%s" cannot be read as it is abstract.', $class->getName()));
throw new \InvalidArgumentException(\sprintf('Attributes from class "%s" cannot be read as it is abstract.', $class->getName()));
}
$this->hasDeprecatedAnnotations = false;
$globals = $this->getGlobals($class);
$collection = new RouteCollection();
$collection->addResource(new FileResource($class->getFileName()));
if ($globals['env'] && $this->env !== $globals['env']) {
return $collection;
}
$fqcnAlias = false;
try {
$globals = $this->getGlobals($class);
$collection = new RouteCollection();
$collection->addResource(new FileResource($class->getFileName()));
if ($globals['env'] && $this->env !== $globals['env']) {
return $collection;
}
$fqcnAlias = false;
foreach ($class->getMethods() as $method) {
$this->defaultRouteIndex = 0;
$routeNamesBefore = array_keys($collection->all());
foreach ($this->getAnnotations($method) as $annot) {
$this->addRoute($collection, $annot, $globals, $class, $method);
if ('__invoke' === $method->name) {
$fqcnAlias = true;
}
}
if (1 === $collection->count() - \count($routeNamesBefore)) {
$newRouteName = current(array_diff(array_keys($collection->all()), $routeNamesBefore));
if ($newRouteName !== $aliasName = sprintf('%s::%s', $class->name, $method->name)) {
$collection->addAlias($aliasName, $newRouteName);
}
if (!$class->hasMethod('__invoke')) {
foreach ($this->getAttributes($class) as $attr) {
if ($attr->getAliases()) {
throw new InvalidArgumentException(\sprintf('Route aliases cannot be used on non-invokable class "%s".', $class->getName()));
}
}
if (0 === $collection->count() && $class->hasMethod('__invoke')) {
$globals = $this->resetGlobals();
foreach ($this->getAnnotations($class) as $annot) {
$this->addRoute($collection, $annot, $globals, $class, $class->getMethod('__invoke'));
}
foreach ($class->getMethods() as $method) {
$this->defaultRouteIndex = 0;
$routeNamesBefore = array_keys($collection->all());
foreach ($this->getAttributes($method) as $attr) {
$this->addRoute($collection, $attr, $globals, $class, $method);
if ('__invoke' === $method->name) {
$fqcnAlias = true;
}
}
if ($fqcnAlias && 1 === $collection->count()) {
$invokeRouteName = key($collection->all());
if ($invokeRouteName !== $class->name) {
$collection->addAlias($class->name, $invokeRouteName);
}
if ($invokeRouteName !== $aliasName = sprintf('%s::__invoke', $class->name)) {
$collection->addAlias($aliasName, $invokeRouteName);
if (1 === $collection->count() - \count($routeNamesBefore)) {
$newRouteName = current(array_diff(array_keys($collection->all()), $routeNamesBefore));
if ($newRouteName !== $aliasName = \sprintf('%s::%s', $class->name, $method->name)) {
$collection->addAlias($aliasName, $newRouteName);
}
}
if ($this->hasDeprecatedAnnotations) {
trigger_deprecation('symfony/routing', '6.4', 'Class "%s" uses Doctrine Annotations to configure routes, which is deprecated. Use PHP attributes instead.', $class->getName());
}
if (0 === $collection->count() && $class->hasMethod('__invoke')) {
$globals = $this->resetGlobals();
foreach ($this->getAttributes($class) as $attr) {
$this->addRoute($collection, $attr, $globals, $class, $class->getMethod('__invoke'));
$fqcnAlias = true;
}
}
if ($fqcnAlias && 1 === $collection->count()) {
$invokeRouteName = key($collection->all());
if ($invokeRouteName !== $class->name) {
$collection->addAlias($class->name, $invokeRouteName);
}
if ($invokeRouteName !== $aliasName = \sprintf('%s::__invoke', $class->name)) {
$collection->addAlias($aliasName, $invokeRouteName);
}
} finally {
$this->hasDeprecatedAnnotations = false;
}
return $collection;
}
/**
* @param RouteAnnotation $annot or an object that exposes a similar interface
*
* @return void
* @param RouteAttribute $attr or an object that exposes a similar interface
*/
protected function addRoute(RouteCollection $collection, object $annot, array $globals, \ReflectionClass $class, \ReflectionMethod $method)
protected function addRoute(RouteCollection $collection, object $attr, array $globals, \ReflectionClass $class, \ReflectionMethod $method): void
{
if ($annot->getEnv() && $annot->getEnv() !== $this->env) {
if ($attr->getEnv() && $attr->getEnv() !== $this->env) {
return;
}
$name = $annot->getName() ?? $this->getDefaultRouteName($class, $method);
$name = $attr->getName() ?? $this->getDefaultRouteName($class, $method);
$name = $globals['name'].$name;
$requirements = $annot->getRequirements();
$requirements = $attr->getRequirements();
foreach ($requirements as $placeholder => $requirement) {
if (\is_int($placeholder)) {
throw new \InvalidArgumentException(sprintf('A placeholder name must be a string (%d given). Did you forget to specify the placeholder key for the requirement "%s" of route "%s" in "%s::%s()"?', $placeholder, $requirement, $name, $class->getName(), $method->getName()));
throw new \InvalidArgumentException(\sprintf('A placeholder name must be a string (%d given). Did you forget to specify the placeholder key for the requirement "%s" of route "%s" in "%s::%s()"?', $placeholder, $requirement, $name, $class->getName(), $method->getName()));
}
}
$defaults = array_replace($globals['defaults'], $annot->getDefaults());
$defaults = array_replace($globals['defaults'], $attr->getDefaults());
$requirements = array_replace($globals['requirements'], $requirements);
$options = array_replace($globals['options'], $annot->getOptions());
$schemes = array_unique(array_merge($globals['schemes'], $annot->getSchemes()));
$methods = array_unique(array_merge($globals['methods'], $annot->getMethods()));
$options = array_replace($globals['options'], $attr->getOptions());
$schemes = array_unique(array_merge($globals['schemes'], $attr->getSchemes()));
$methods = array_unique(array_merge($globals['methods'], $attr->getMethods()));
$host = $annot->getHost() ?? $globals['host'];
$condition = $annot->getCondition() ?? $globals['condition'];
$priority = $annot->getPriority() ?? $globals['priority'];
$host = $attr->getHost() ?? $globals['host'];
$condition = $attr->getCondition() ?? $globals['condition'];
$priority = $attr->getPriority() ?? $globals['priority'];
$path = $annot->getLocalizedPaths() ?: $annot->getPath();
$path = $attr->getLocalizedPaths() ?: $attr->getPath();
$prefix = $globals['localized_paths'] ?: $globals['path'];
$paths = [];
@@ -219,11 +196,11 @@ abstract class AttributeClassLoader implements LoaderInterface
$paths[$locale] = $prefix.$localePath;
}
} elseif ($missing = array_diff_key($prefix, $path)) {
throw new \LogicException(sprintf('Route to "%s" is missing paths for locale(s) "%s".', $class->name.'::'.$method->name, implode('", "', array_keys($missing))));
throw new \LogicException(\sprintf('Route to "%s" is missing paths for locale(s) "%s".', $class->name.'::'.$method->name, implode('", "', array_keys($missing))));
} else {
foreach ($path as $locale => $localePath) {
if (!isset($prefix[$locale])) {
throw new \LogicException(sprintf('Route to "%s" with locale "%s" is missing a corresponding prefix in class "%s".', $method->name, $locale, $class->name));
throw new \LogicException(\sprintf('Route to "%s" with locale "%s" is missing a corresponding prefix in class "%s".', $method->name, $locale, $class->name));
}
$paths[$locale] = $prefix[$locale].$localePath;
@@ -242,7 +219,7 @@ abstract class AttributeClassLoader implements LoaderInterface
continue;
}
foreach ($paths as $locale => $path) {
if (preg_match(sprintf('/\{%s(?:<.*?>)?\}/', preg_quote($param->name)), $path)) {
if (preg_match(\sprintf('/\{%s(?:<.*?>)?\}/', preg_quote($param->name)), $path)) {
if (\is_scalar($defaultValue = $param->getDefaultValue()) || null === $defaultValue) {
$defaults[$param->name] = $defaultValue;
} elseif ($defaultValue instanceof \BackedEnum) {
@@ -255,7 +232,7 @@ abstract class AttributeClassLoader implements LoaderInterface
foreach ($paths as $locale => $path) {
$route = $this->createRoute($path, $defaults, $requirements, $options, $host, $schemes, $methods, $condition);
$this->configureRoute($route, $class, $method, $annot);
$this->configureRoute($route, $class, $method, $attr);
if (0 !== $locale) {
$route->setDefault('_locale', $locale);
$route->setRequirement('_locale', preg_quote($locale));
@@ -264,16 +241,25 @@ abstract class AttributeClassLoader implements LoaderInterface
} else {
$collection->add($name, $route, $priority);
}
foreach ($attr->getAliases() as $aliasAttribute) {
if ($aliasAttribute instanceof DeprecatedAlias) {
$alias = $collection->addAlias($aliasAttribute->getAliasName(), $name);
$alias->setDeprecated(
$aliasAttribute->getPackage(),
$aliasAttribute->getVersion(),
$aliasAttribute->getMessage()
);
continue;
}
$collection->addAlias($aliasAttribute, $name);
}
}
}
public function supports(mixed $resource, ?string $type = null): bool
{
if ('annotation' === $type) {
trigger_deprecation('symfony/routing', '6.4', 'The "annotation" route type is deprecated, use the "attribute" route type instead.');
}
return \is_string($resource) && preg_match('/^(?:\\\\?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)+$/', $resource) && (!$type || \in_array($type, ['annotation', 'attribute'], true));
return \is_string($resource) && preg_match('/^(?:\\\\?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)+$/', $resource) && (!$type || 'attribute' === $type);
}
public function setResolver(LoaderResolverInterface $resolver): void
@@ -282,6 +268,7 @@ abstract class AttributeClassLoader implements LoaderInterface
public function getResolver(): LoaderResolverInterface
{
throw new LogicException(\sprintf('The "%s()" method must not be called.', __METHOD__));
}
/**
@@ -304,63 +291,58 @@ abstract class AttributeClassLoader implements LoaderInterface
/**
* @return array<string, mixed>
*/
protected function getGlobals(\ReflectionClass $class)
protected function getGlobals(\ReflectionClass $class): array
{
$globals = $this->resetGlobals();
$annot = null;
// to be replaced in Symfony 8.0 by $this->routeAttributeClass
if ($attribute = $class->getAttributes($this->routeAnnotationClass, \ReflectionAttribute::IS_INSTANCEOF)[0] ?? null) {
$annot = $attribute->newInstance();
}
if (!$annot && $annot = $this->reader?->getClassAnnotation($class, $this->routeAnnotationClass)) {
$this->hasDeprecatedAnnotations = true;
}
$attr = $attribute->newInstance();
if ($annot) {
if (null !== $annot->getName()) {
$globals['name'] = $annot->getName();
if (null !== $attr->getName()) {
$globals['name'] = $attr->getName();
}
if (null !== $annot->getPath()) {
$globals['path'] = $annot->getPath();
if (null !== $attr->getPath()) {
$globals['path'] = $attr->getPath();
}
$globals['localized_paths'] = $annot->getLocalizedPaths();
$globals['localized_paths'] = $attr->getLocalizedPaths();
if (null !== $annot->getRequirements()) {
$globals['requirements'] = $annot->getRequirements();
if (null !== $attr->getRequirements()) {
$globals['requirements'] = $attr->getRequirements();
}
if (null !== $annot->getOptions()) {
$globals['options'] = $annot->getOptions();
if (null !== $attr->getOptions()) {
$globals['options'] = $attr->getOptions();
}
if (null !== $annot->getDefaults()) {
$globals['defaults'] = $annot->getDefaults();
if (null !== $attr->getDefaults()) {
$globals['defaults'] = $attr->getDefaults();
}
if (null !== $annot->getSchemes()) {
$globals['schemes'] = $annot->getSchemes();
if (null !== $attr->getSchemes()) {
$globals['schemes'] = $attr->getSchemes();
}
if (null !== $annot->getMethods()) {
$globals['methods'] = $annot->getMethods();
if (null !== $attr->getMethods()) {
$globals['methods'] = $attr->getMethods();
}
if (null !== $annot->getHost()) {
$globals['host'] = $annot->getHost();
if (null !== $attr->getHost()) {
$globals['host'] = $attr->getHost();
}
if (null !== $annot->getCondition()) {
$globals['condition'] = $annot->getCondition();
if (null !== $attr->getCondition()) {
$globals['condition'] = $attr->getCondition();
}
$globals['priority'] = $annot->getPriority() ?? 0;
$globals['env'] = $annot->getEnv();
$globals['priority'] = $attr->getPriority() ?? 0;
$globals['env'] = $attr->getEnv();
foreach ($globals['requirements'] as $placeholder => $requirement) {
if (\is_int($placeholder)) {
throw new \InvalidArgumentException(sprintf('A placeholder name must be a string (%d given). Did you forget to specify the placeholder key for the requirement "%s" in "%s"?', $placeholder, $requirement, $class->getName()));
throw new \InvalidArgumentException(\sprintf('A placeholder name must be a string (%d given). Did you forget to specify the placeholder key for the requirement "%s" in "%s"?', $placeholder, $requirement, $class->getName()));
}
}
}
@@ -386,46 +368,26 @@ abstract class AttributeClassLoader implements LoaderInterface
];
}
/**
* @return Route
*/
protected function createRoute(string $path, array $defaults, array $requirements, array $options, ?string $host, array $schemes, array $methods, ?string $condition)
protected function createRoute(string $path, array $defaults, array $requirements, array $options, ?string $host, array $schemes, array $methods, ?string $condition): Route
{
return new Route($path, $defaults, $requirements, $options, $host, $schemes, $methods, $condition);
}
/**
* @param RouteAttribute $attr or an object that exposes a similar interface
*
* @return void
*/
abstract protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, object $annot);
abstract protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, object $attr);
/**
* @return iterable<int, RouteAnnotation>
* @return iterable<int, RouteAttribute>
*/
private function getAnnotations(\ReflectionClass|\ReflectionMethod $reflection): iterable
private function getAttributes(\ReflectionClass|\ReflectionMethod $reflection): iterable
{
// to be replaced in Symfony 8.0 by $this->routeAttributeClass
foreach ($reflection->getAttributes($this->routeAnnotationClass, \ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
yield $attribute->newInstance();
}
if (!$this->reader) {
return;
}
$annotations = $reflection instanceof \ReflectionClass
? $this->reader->getClassAnnotations($reflection)
: $this->reader->getMethodAnnotations($reflection);
foreach ($annotations as $annotation) {
if ($annotation instanceof $this->routeAnnotationClass) {
$this->hasDeprecatedAnnotations = true;
yield $annotation;
}
}
}
}
if (!class_exists(AnnotationClassLoader::class, false)) {
class_alias(AttributeClassLoader::class, AnnotationClassLoader::class);
}

View File

@@ -67,11 +67,7 @@ class AttributeDirectoryLoader extends AttributeFileLoader
return false;
}
if (\in_array($type, ['annotation', 'attribute'], true)) {
if ('annotation' === $type) {
trigger_deprecation('symfony/routing', '6.4', 'The "annotation" route type is deprecated, use the "attribute" route type instead.');
}
if ('attribute' === $type) {
return true;
}
@@ -86,7 +82,3 @@ class AttributeDirectoryLoader extends AttributeFileLoader
}
}
}
if (!class_exists(AnnotationDirectoryLoader::class, false)) {
class_alias(AttributeDirectoryLoader::class, AnnotationDirectoryLoader::class);
}

View File

@@ -25,17 +25,15 @@ use Symfony\Component\Routing\RouteCollection;
*/
class AttributeFileLoader extends FileLoader
{
protected $loader;
public function __construct(FileLocatorInterface $locator, AttributeClassLoader $loader)
{
public function __construct(
FileLocatorInterface $locator,
protected AttributeClassLoader $loader,
) {
if (!\function_exists('token_get_all')) {
throw new \LogicException('The Tokenizer extension is required for the routing attribute loader.');
}
parent::__construct($locator);
$this->loader = $loader;
}
/**
@@ -65,11 +63,7 @@ class AttributeFileLoader extends FileLoader
public function supports(mixed $resource, ?string $type = null): bool
{
if ('annotation' === $type) {
trigger_deprecation('symfony/routing', '6.4', 'The "annotation" route type is deprecated, use the "attribute" route type instead.');
}
return \is_string($resource) && 'php' === pathinfo($resource, \PATHINFO_EXTENSION) && (!$type || \in_array($type, ['annotation', 'attribute'], true));
return \is_string($resource) && 'php' === pathinfo($resource, \PATHINFO_EXTENSION) && (!$type || 'attribute' === $type);
}
/**
@@ -82,7 +76,7 @@ class AttributeFileLoader extends FileLoader
$tokens = token_get_all(file_get_contents($file));
if (1 === \count($tokens) && \T_INLINE_HTML === $tokens[0][0]) {
throw new \InvalidArgumentException(sprintf('The file "%s" does not contain PHP code. Did you forgot to add the "<?php" start tag at the beginning of the file?', $file));
throw new \InvalidArgumentException(\sprintf('The file "%s" does not contain PHP code. Did you forget to add the "<?php" start tag at the beginning of the file?', $file));
}
$nsTokens = [\T_NS_SEPARATOR => true, \T_STRING => true];
@@ -139,7 +133,3 @@ class AttributeFileLoader extends FileLoader
return false;
}
}
if (!class_exists(AnnotationFileLoader::class, false)) {
class_alias(AttributeFileLoader::class, AnnotationFileLoader::class);
}

View File

@@ -16,11 +16,9 @@ use Symfony\Component\Routing\Alias;
class AliasConfigurator
{
private Alias $alias;
public function __construct(Alias $alias)
{
$this->alias = $alias;
public function __construct(
private Alias $alias,
) {
}
/**

View File

@@ -23,19 +23,17 @@ class CollectionConfigurator
use Traits\HostTrait;
use Traits\RouteTrait;
private RouteCollection $parent;
private ?CollectionConfigurator $parentConfigurator;
private ?array $parentPrefixes;
private string|array|null $host = null;
public function __construct(RouteCollection $parent, string $name, ?self $parentConfigurator = null, ?array $parentPrefixes = null)
{
$this->parent = $parent;
public function __construct(
private RouteCollection $parent,
string $name,
private ?self $parentConfigurator = null, // for GC control
private ?array $parentPrefixes = null,
) {
$this->name = $name;
$this->collection = new RouteCollection();
$this->route = new Route('');
$this->parentConfigurator = $parentConfigurator; // for GC control
$this->parentPrefixes = $parentPrefixes;
}
public function __sleep(): array
@@ -43,10 +41,7 @@ class CollectionConfigurator
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
}
/**
* @return void
*/
public function __wakeup()
public function __wakeup(): void
{
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
}
@@ -84,11 +79,11 @@ class CollectionConfigurator
if (null === $this->parentPrefixes) {
// no-op
} elseif ($missing = array_diff_key($this->parentPrefixes, $prefix)) {
throw new \LogicException(sprintf('Collection "%s" is missing prefixes for locale(s) "%s".', $this->name, implode('", "', array_keys($missing))));
throw new \LogicException(\sprintf('Collection "%s" is missing prefixes for locale(s) "%s".', $this->name, implode('", "', array_keys($missing))));
} else {
foreach ($prefix as $locale => $localePrefix) {
if (!isset($this->parentPrefixes[$locale])) {
throw new \LogicException(sprintf('Collection "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $this->name, $locale));
throw new \LogicException(\sprintf('Collection "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $this->name, $locale));
}
$prefix[$locale] = $this->parentPrefixes[$locale].$localePrefix;

View File

@@ -22,11 +22,10 @@ class ImportConfigurator
use Traits\PrefixTrait;
use Traits\RouteTrait;
private RouteCollection $parent;
public function __construct(RouteCollection $parent, RouteCollection $route)
{
$this->parent = $parent;
public function __construct(
private RouteCollection $parent,
RouteCollection $route,
) {
$this->route = $route;
}
@@ -35,10 +34,7 @@ class ImportConfigurator
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
}
/**
* @return void
*/
public function __wakeup()
public function __wakeup(): void
{
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
}

View File

@@ -22,14 +22,16 @@ class RouteConfigurator
use Traits\HostTrait;
use Traits\RouteTrait;
protected $parentConfigurator;
public function __construct(RouteCollection $collection, RouteCollection $route, string $name = '', ?CollectionConfigurator $parentConfigurator = null, ?array $prefixes = null)
{
public function __construct(
RouteCollection $collection,
RouteCollection $route,
string $name = '',
protected ?CollectionConfigurator $parentConfigurator = null, // for GC control
?array $prefixes = null,
) {
$this->collection = $collection;
$this->route = $route;
$this->name = $name;
$this->parentConfigurator = $parentConfigurator; // for GC control
$this->prefixes = $prefixes;
}
@@ -42,7 +44,14 @@ class RouteConfigurator
*/
final public function host(string|array $host): static
{
$previousRoutes = clone $this->route;
$this->addHost($this->route, $host);
foreach ($previousRoutes as $name => $route) {
if (!$this->route->get($name)) {
$this->collection->remove($name);
}
}
$this->collection->addCollection($this->route);
return $this;
}

View File

@@ -21,18 +21,14 @@ class RoutingConfigurator
{
use Traits\AddTrait;
private PhpFileLoader $loader;
private string $path;
private string $file;
private ?string $env;
public function __construct(RouteCollection $collection, PhpFileLoader $loader, string $path, string $file, ?string $env = null)
{
public function __construct(
RouteCollection $collection,
private PhpFileLoader $loader,
private string $path,
private string $file,
private ?string $env = null,
) {
$this->collection = $collection;
$this->loader = $loader;
$this->path = $path;
$this->file = $file;
$this->env = $env;
}
/**

View File

@@ -23,12 +23,9 @@ trait AddTrait
{
use LocalizedRouteTrait;
/**
* @var RouteCollection
*/
protected $collection;
protected $name = '';
protected $prefixes;
protected RouteCollection $collection;
protected string $name = '';
protected ?array $prefixes = null;
/**
* Adds a route.

View File

@@ -28,6 +28,7 @@ trait HostTrait
foreach ($routes->all() as $name => $route) {
if (null === $locale = $route->getDefault('_locale')) {
$priority = $routes->getPriority($name) ?? 0;
$routes->remove($name);
foreach ($hosts as $locale => $host) {
$localizedRoute = clone $route;
@@ -35,14 +36,14 @@ trait HostTrait
$localizedRoute->setRequirement('_locale', preg_quote($locale));
$localizedRoute->setDefault('_canonical_route', $name);
$localizedRoute->setHost($host);
$routes->add($name.'.'.$locale, $localizedRoute);
$routes->add($name.'.'.$locale, $localizedRoute, $priority);
}
} elseif (!isset($hosts[$locale])) {
throw new \InvalidArgumentException(sprintf('Route "%s" with locale "%s" is missing a corresponding host in its parent collection.', $name, $locale));
throw new \InvalidArgumentException(\sprintf('Route "%s" with locale "%s" is missing a corresponding host in its parent collection.', $name, $locale));
} else {
$route->setHost($hosts[$locale]);
$route->setRequirement('_locale', preg_quote($locale));
$routes->add($name, $route);
$routes->add($name, $route, $routes->getPriority($name) ?? 0);
}
}
}

View File

@@ -37,11 +37,11 @@ trait LocalizedRouteTrait
if (null === $prefixes) {
$paths = $path;
} elseif ($missing = array_diff_key($prefixes, $path)) {
throw new \LogicException(sprintf('Route "%s" is missing routes for locale(s) "%s".', $name, implode('", "', array_keys($missing))));
throw new \LogicException(\sprintf('Route "%s" is missing routes for locale(s) "%s".', $name, implode('", "', array_keys($missing))));
} else {
foreach ($path as $locale => $localePath) {
if (!isset($prefixes[$locale])) {
throw new \LogicException(sprintf('Route "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $name, $locale));
throw new \LogicException(\sprintf('Route "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $name, $locale));
}
$paths[$locale] = $prefixes[$locale].$localePath;

View File

@@ -40,7 +40,7 @@ trait PrefixTrait
$routes->add($name.'.'.$locale, $localizedRoute, $priority);
}
} elseif (!isset($prefix[$locale])) {
throw new \InvalidArgumentException(sprintf('Route "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $name, $locale));
throw new \InvalidArgumentException(\sprintf('Route "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $name, $locale));
} else {
$route->setPath($prefix[$locale].(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath()));
$routes->add($name, $route, $routes->getPriority($name) ?? 0);

View File

@@ -16,10 +16,7 @@ use Symfony\Component\Routing\RouteCollection;
trait RouteTrait
{
/**
* @var RouteCollection|Route
*/
protected $route;
protected RouteCollection|Route $route;
/**
* Adds defaults.

View File

@@ -20,11 +20,10 @@ use Psr\Container\ContainerInterface;
*/
class ContainerLoader extends ObjectLoader
{
private ContainerInterface $container;
public function __construct(ContainerInterface $container, ?string $env = null)
{
$this->container = $container;
public function __construct(
private ContainerInterface $container,
?string $env = null,
) {
parent::__construct($env);
}

View File

@@ -36,7 +36,7 @@ abstract class ObjectLoader extends Loader
public function load(mixed $resource, ?string $type = null): RouteCollection
{
if (!preg_match('/^[^\:]+(?:::(?:[^\:]+))?$/', $resource)) {
throw new \InvalidArgumentException(sprintf('Invalid resource "%s" passed to the %s route loader: use the format "object_id::method" or "object_id" if your object class has an "__invoke" method.', $resource, \is_string($type) ? '"'.$type.'"' : 'object'));
throw new \InvalidArgumentException(\sprintf('Invalid resource "%s" passed to the %s route loader: use the format "object_id::method" or "object_id" if your object class has an "__invoke" method.', $resource, \is_string($type) ? '"'.$type.'"' : 'object'));
}
$parts = explode('::', $resource);
@@ -44,12 +44,8 @@ abstract class ObjectLoader extends Loader
$loaderObject = $this->getObject($parts[0]);
if (!\is_object($loaderObject)) {
throw new \TypeError(sprintf('"%s:getObject()" must return an object: "%s" returned.', static::class, get_debug_type($loaderObject)));
}
if (!\is_callable([$loaderObject, $method])) {
throw new \BadMethodCallException(sprintf('Method "%s" not found on "%s" when importing routing resource "%s".', $method, get_debug_type($loaderObject), $resource));
throw new \BadMethodCallException(\sprintf('Method "%s" not found on "%s" when importing routing resource "%s".', $method, get_debug_type($loaderObject), $resource));
}
$routeCollection = $loaderObject->$method($this, $this->env);
@@ -57,7 +53,7 @@ abstract class ObjectLoader extends Loader
if (!$routeCollection instanceof RouteCollection) {
$type = get_debug_type($routeCollection);
throw new \LogicException(sprintf('The "%s::%s()" method must return a RouteCollection: "%s" returned.', get_debug_type($loaderObject), $method, $type));
throw new \LogicException(\sprintf('The "%s::%s()" method must return a RouteCollection: "%s" returned.', get_debug_type($loaderObject), $method, $type));
}
// make the object file tracked so that if it changes, the cache rebuilds

View File

@@ -15,6 +15,7 @@ use Symfony\Component\Config\FileLocatorInterface;
use Symfony\Component\Config\Loader\DirectoryAwareLoaderInterface;
use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\Config\Resource\DirectoryResource;
use Symfony\Component\Routing\Exception\InvalidArgumentException;
use Symfony\Component\Routing\RouteCollection;
/**
@@ -43,12 +44,16 @@ final class Psr4DirectoryLoader extends Loader implements DirectoryAwareLoaderIn
return new RouteCollection();
}
if (!preg_match('/^(?:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+\\\)++$/', trim($resource['namespace'], '\\').'\\')) {
throw new InvalidArgumentException(\sprintf('Namespace "%s" is not a valid PSR-4 prefix.', $resource['namespace']));
}
return $this->loadFromDirectory($path, trim($resource['namespace'], '\\'));
}
public function supports(mixed $resource, ?string $type = null): bool
{
return ('attribute' === $type || 'annotation' === $type) && \is_array($resource) && isset($resource['path'], $resource['namespace']);
return 'attribute' === $type && \is_array($resource) && isset($resource['path'], $resource['namespace']);
}
public function forDirectory(string $currentDirectory): static

View File

@@ -62,11 +62,9 @@ class XmlFileLoader extends FileLoader
/**
* Parses a node from a loaded XML file.
*
* @return void
*
* @throws \InvalidArgumentException When the XML is invalid
*/
protected function parseNode(RouteCollection $collection, \DOMElement $node, string $path, string $file)
protected function parseNode(RouteCollection $collection, \DOMElement $node, string $path, string $file): void
{
if (self::NAMESPACE_URI !== $node->namespaceURI) {
return;
@@ -90,7 +88,7 @@ class XmlFileLoader extends FileLoader
}
break;
default:
throw new \InvalidArgumentException(sprintf('Unknown tag "%s" used in file "%s". Expected "route" or "import".', $node->localName, $path));
throw new \InvalidArgumentException(\sprintf('Unknown tag "%s" used in file "%s". Expected "route" or "import".', $node->localName, $path));
}
}
@@ -102,14 +100,12 @@ class XmlFileLoader extends FileLoader
/**
* Parses a route and adds it to the RouteCollection.
*
* @return void
*
* @throws \InvalidArgumentException When the XML is invalid
*/
protected function parseRoute(RouteCollection $collection, \DOMElement $node, string $path)
protected function parseRoute(RouteCollection $collection, \DOMElement $node, string $path): void
{
if ('' === $id = $node->getAttribute('id')) {
throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" must have an "id" attribute.', $path));
throw new \InvalidArgumentException(\sprintf('The <route> element in file "%s" must have an "id" attribute.', $path));
}
if ('' !== $alias = $node->getAttribute('alias')) {
@@ -128,14 +124,14 @@ class XmlFileLoader extends FileLoader
[$defaults, $requirements, $options, $condition, $paths, /* $prefixes */, $hosts] = $this->parseConfigs($node, $path);
if (!$paths && '' === $node->getAttribute('path')) {
throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" must have a "path" attribute or <path> child nodes.', $path));
throw new \InvalidArgumentException(\sprintf('The <route> element in file "%s" must have a "path" attribute or <path> child nodes.', $path));
}
if ($paths && '' !== $node->getAttribute('path')) {
throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" must not have both a "path" attribute and <path> child nodes.', $path));
throw new \InvalidArgumentException(\sprintf('The <route> element in file "%s" must not have both a "path" attribute and <path> child nodes.', $path));
}
$routes = $this->createLocalizedRoute($collection, $id, $paths ?: $node->getAttribute('path'));
$routes = $this->createLocalizedRoute(new RouteCollection(), $id, $paths ?: $node->getAttribute('path'));
$routes->addDefaults($defaults);
$routes->addRequirements($requirements);
$routes->addOptions($options);
@@ -146,16 +142,16 @@ class XmlFileLoader extends FileLoader
if (null !== $hosts) {
$this->addHost($routes, $hosts);
}
$collection->addCollection($routes);
}
/**
* Parses an import and adds the routes in the resource to the RouteCollection.
*
* @return void
*
* @throws \InvalidArgumentException When the XML is invalid
*/
protected function parseImport(RouteCollection $collection, \DOMElement $node, string $path, string $file)
protected function parseImport(RouteCollection $collection, \DOMElement $node, string $path, string $file): void
{
/** @var \DOMElement $resourceElement */
if (!($resource = $node->getAttribute('resource') ?: null) && $resourceElement = $node->getElementsByTagName('resource')[0] ?? null) {
@@ -167,7 +163,7 @@ class XmlFileLoader extends FileLoader
}
if (!$resource) {
throw new \InvalidArgumentException(sprintf('The <import> element in file "%s" must have a "resource" attribute or element.', $path));
throw new \InvalidArgumentException(\sprintf('The <import> element in file "%s" must have a "resource" attribute or element.', $path));
}
$type = $node->getAttribute('type');
@@ -180,7 +176,7 @@ class XmlFileLoader extends FileLoader
[$defaults, $requirements, $options, $condition, /* $paths */, $prefixes, $hosts] = $this->parseConfigs($node, $path);
if ('' !== $prefix && $prefixes) {
throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" must not have both a "prefix" attribute and <prefix> child nodes.', $path));
throw new \InvalidArgumentException(\sprintf('The <route> element in file "%s" must not have both a "prefix" attribute and <prefix> child nodes.', $path));
}
$exclude = [];
@@ -294,15 +290,15 @@ class XmlFileLoader extends FileLoader
case 'resource':
break;
default:
throw new \InvalidArgumentException(sprintf('Unknown tag "%s" used in file "%s". Expected "default", "requirement", "option" or "condition".', $n->localName, $path));
throw new \InvalidArgumentException(\sprintf('Unknown tag "%s" used in file "%s". Expected "default", "requirement", "option" or "condition".', $n->localName, $path));
}
}
if ($controller = $node->getAttribute('controller')) {
if (isset($defaults['_controller'])) {
$name = $node->hasAttribute('id') ? sprintf('"%s".', $node->getAttribute('id')) : sprintf('the "%s" tag.', $node->tagName);
$name = $node->hasAttribute('id') ? \sprintf('"%s".', $node->getAttribute('id')) : \sprintf('the "%s" tag.', $node->tagName);
throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "controller" attribute and the defaults key "_controller" for ', $path).$name);
throw new \InvalidArgumentException(\sprintf('The routing file "%s" must not specify both the "controller" attribute and the defaults key "_controller" for ', $path).$name);
}
$defaults['_controller'] = $controller;
@@ -318,9 +314,9 @@ class XmlFileLoader extends FileLoader
}
if ($stateless = $node->getAttribute('stateless')) {
if (isset($defaults['_stateless'])) {
$name = $node->hasAttribute('id') ? sprintf('"%s".', $node->getAttribute('id')) : sprintf('the "%s" tag.', $node->tagName);
$name = $node->hasAttribute('id') ? \sprintf('"%s".', $node->getAttribute('id')) : \sprintf('the "%s" tag.', $node->tagName);
throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "stateless" attribute and the defaults key "_stateless" for ', $path).$name);
throw new \InvalidArgumentException(\sprintf('The routing file "%s" must not specify both the "stateless" attribute and the defaults key "_stateless" for ', $path).$name);
}
$defaults['_stateless'] = XmlUtils::phpize($stateless);
@@ -416,7 +412,7 @@ class XmlFileLoader extends FileLoader
return $map;
default:
throw new \InvalidArgumentException(sprintf('Unknown tag "%s" used in file "%s". Expected "bool", "int", "float", "string", "list", or "map".', $node->localName, $path));
throw new \InvalidArgumentException(\sprintf('Unknown tag "%s" used in file "%s". Expected "bool", "int", "float", "string", "list", or "map".', $node->localName, $path));
}
}
@@ -444,7 +440,7 @@ class XmlFileLoader extends FileLoader
continue;
}
if ('deprecated' !== $child->localName) {
throw new \InvalidArgumentException(sprintf('Invalid child element "%s" defined for alias "%s" in "%s".', $child->localName, $node->getAttribute('id'), $path));
throw new \InvalidArgumentException(\sprintf('Invalid child element "%s" defined for alias "%s" in "%s".', $child->localName, $node->getAttribute('id'), $path));
}
$deprecatedNode = $child;
@@ -455,10 +451,10 @@ class XmlFileLoader extends FileLoader
}
if (!$deprecatedNode->hasAttribute('package')) {
throw new \InvalidArgumentException(sprintf('The <deprecated> element in file "%s" must have a "package" attribute.', $path));
throw new \InvalidArgumentException(\sprintf('The <deprecated> element in file "%s" must have a "package" attribute.', $path));
}
if (!$deprecatedNode->hasAttribute('version')) {
throw new \InvalidArgumentException(sprintf('The <deprecated> element in file "%s" must have a "version" attribute.', $path));
throw new \InvalidArgumentException(\sprintf('The <deprecated> element in file "%s" must have a "version" attribute.', $path));
}
return [

View File

@@ -46,11 +46,11 @@ class YamlFileLoader extends FileLoader
$path = $this->locator->locate($file);
if (!stream_is_local($path)) {
throw new \InvalidArgumentException(sprintf('This is not a local file "%s".', $path));
throw new \InvalidArgumentException(\sprintf('This is not a local file "%s".', $path));
}
if (!file_exists($path)) {
throw new \InvalidArgumentException(sprintf('File "%s" not found.', $path));
throw new \InvalidArgumentException(\sprintf('File "%s" not found.', $path));
}
$this->yamlParser ??= new YamlParser();
@@ -58,7 +58,7 @@ class YamlFileLoader extends FileLoader
try {
$parsedConfig = $this->yamlParser->parseFile($path, Yaml::PARSE_CONSTANT);
} catch (ParseException $e) {
throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML: ', $path).$e->getMessage(), 0, $e);
throw new \InvalidArgumentException(\sprintf('The file "%s" does not contain valid YAML: ', $path).$e->getMessage(), 0, $e);
}
$collection = new RouteCollection();
@@ -71,7 +71,7 @@ class YamlFileLoader extends FileLoader
// not an array
if (!\is_array($parsedConfig)) {
throw new \InvalidArgumentException(sprintf('The file "%s" must contain a YAML array.', $path));
throw new \InvalidArgumentException(\sprintf('The file "%s" must contain a YAML array.', $path));
}
foreach ($parsedConfig as $name => $config) {
@@ -112,10 +112,8 @@ class YamlFileLoader extends FileLoader
/**
* Parses a route and adds it to the RouteCollection.
*
* @return void
*/
protected function parseRoute(RouteCollection $collection, string $name, array $config, string $path)
protected function parseRoute(RouteCollection $collection, string $name, array $config, string $path): void
{
if (isset($config['alias'])) {
$alias = $collection->addAlias($name, $config['alias']);
@@ -137,7 +135,7 @@ class YamlFileLoader extends FileLoader
foreach ($requirements as $placeholder => $requirement) {
if (\is_int($placeholder)) {
throw new \InvalidArgumentException(sprintf('A placeholder name must be a string (%d given). Did you forget to specify the placeholder key for the requirement "%s" of route "%s" in "%s"?', $placeholder, $requirement, $name, $path));
throw new \InvalidArgumentException(\sprintf('A placeholder name must be a string (%d given). Did you forget to specify the placeholder key for the requirement "%s" of route "%s" in "%s"?', $placeholder, $requirement, $name, $path));
}
}
@@ -157,7 +155,7 @@ class YamlFileLoader extends FileLoader
$defaults['_stateless'] = $config['stateless'];
}
$routes = $this->createLocalizedRoute($collection, $name, $config['path']);
$routes = $this->createLocalizedRoute(new RouteCollection(), $name, $config['path']);
$routes->addDefaults($defaults);
$routes->addRequirements($requirements);
$routes->addOptions($options);
@@ -168,14 +166,14 @@ class YamlFileLoader extends FileLoader
if (isset($config['host'])) {
$this->addHost($routes, $config['host']);
}
$collection->addCollection($routes);
}
/**
* Parses an import and adds the routes in the resource to the RouteCollection.
*
* @return void
*/
protected function parseImport(RouteCollection $collection, array $config, string $path, string $file)
protected function parseImport(RouteCollection $collection, array $config, string $path, string $file): void
{
$type = $config['type'] ?? null;
$prefix = $config['prefix'] ?? '';
@@ -242,15 +240,13 @@ class YamlFileLoader extends FileLoader
}
/**
* @return void
*
* @throws \InvalidArgumentException If one of the provided config keys is not supported,
* something is missing or the combination is nonsense
*/
protected function validate(mixed $config, string $name, string $path)
protected function validate(mixed $config, string $name, string $path): void
{
if (!\is_array($config)) {
throw new \InvalidArgumentException(sprintf('The definition of "%s" in "%s" must be a YAML array.', $name, $path));
throw new \InvalidArgumentException(\sprintf('The definition of "%s" in "%s" must be a YAML array.', $name, $path));
}
if (isset($config['alias'])) {
$this->validateAlias($config, $name, $path);
@@ -258,22 +254,22 @@ class YamlFileLoader extends FileLoader
return;
}
if ($extraKeys = array_diff(array_keys($config), self::AVAILABLE_KEYS)) {
throw new \InvalidArgumentException(sprintf('The routing file "%s" contains unsupported keys for "%s": "%s". Expected one of: "%s".', $path, $name, implode('", "', $extraKeys), implode('", "', self::AVAILABLE_KEYS)));
throw new \InvalidArgumentException(\sprintf('The routing file "%s" contains unsupported keys for "%s": "%s". Expected one of: "%s".', $path, $name, implode('", "', $extraKeys), implode('", "', self::AVAILABLE_KEYS)));
}
if (isset($config['resource']) && isset($config['path'])) {
throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "resource" key and the "path" key for "%s". Choose between an import and a route definition.', $path, $name));
throw new \InvalidArgumentException(\sprintf('The routing file "%s" must not specify both the "resource" key and the "path" key for "%s". Choose between an import and a route definition.', $path, $name));
}
if (!isset($config['resource']) && isset($config['type'])) {
throw new \InvalidArgumentException(sprintf('The "type" key for the route definition "%s" in "%s" is unsupported. It is only available for imports in combination with the "resource" key.', $name, $path));
throw new \InvalidArgumentException(\sprintf('The "type" key for the route definition "%s" in "%s" is unsupported. It is only available for imports in combination with the "resource" key.', $name, $path));
}
if (!isset($config['resource']) && !isset($config['path'])) {
throw new \InvalidArgumentException(sprintf('You must define a "path" for the route "%s" in file "%s".', $name, $path));
throw new \InvalidArgumentException(\sprintf('You must define a "path" for the route "%s" in file "%s".', $name, $path));
}
if (isset($config['controller']) && isset($config['defaults']['_controller'])) {
throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "controller" key and the defaults key "_controller" for "%s".', $path, $name));
throw new \InvalidArgumentException(\sprintf('The routing file "%s" must not specify both the "controller" key and the defaults key "_controller" for "%s".', $path, $name));
}
if (isset($config['stateless']) && isset($config['defaults']['_stateless'])) {
throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "stateless" key and the defaults key "_stateless" for "%s".', $path, $name));
throw new \InvalidArgumentException(\sprintf('The routing file "%s" must not specify both the "stateless" key and the defaults key "_stateless" for "%s".', $path, $name));
}
}
@@ -285,16 +281,16 @@ class YamlFileLoader extends FileLoader
{
foreach ($config as $key => $value) {
if (!\in_array($key, ['alias', 'deprecated'], true)) {
throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify other keys than "alias" and "deprecated" for "%s".', $path, $name));
throw new \InvalidArgumentException(\sprintf('The routing file "%s" must not specify other keys than "alias" and "deprecated" for "%s".', $path, $name));
}
if ('deprecated' === $key) {
if (!isset($value['package'])) {
throw new \InvalidArgumentException(sprintf('The routing file "%s" must specify the attribute "package" of the "deprecated" option for "%s".', $path, $name));
throw new \InvalidArgumentException(\sprintf('The routing file "%s" must specify the attribute "package" of the "deprecated" option for "%s".', $path, $name));
}
if (!isset($value['version'])) {
throw new \InvalidArgumentException(sprintf('The routing file "%s" must specify the attribute "version" of the "deprecated" option for "%s".', $path, $name));
throw new \InvalidArgumentException(\sprintf('The routing file "%s" must specify the attribute "version" of the "deprecated" option for "%s".', $path, $name));
}
}
}