update patch 1
This commit is contained in:
Vendored
+3
-4
@@ -15,12 +15,11 @@ use Symfony\Component\Routing\Exception\InvalidArgumentException;
|
||||
|
||||
class Alias
|
||||
{
|
||||
private string $id;
|
||||
private array $deprecation = [];
|
||||
|
||||
public function __construct(string $id)
|
||||
{
|
||||
$this->id = $id;
|
||||
public function __construct(
|
||||
private string $id,
|
||||
) {
|
||||
}
|
||||
|
||||
public function withId(string $id): static
|
||||
|
||||
Vendored
+6
@@ -1,6 +1,12 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
7.2
|
||||
---
|
||||
|
||||
* Add the `Requirement::UID_RFC9562` constant to validate UUIDs in the RFC 9562 format
|
||||
* Deprecate the `AttributeClassLoader::$routeAnnotationClass` property
|
||||
|
||||
7.1
|
||||
---
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class MissingMandatoryParametersException extends \InvalidArgumentException impl
|
||||
{
|
||||
$this->routeName = $routeName;
|
||||
$this->missingParameters = $missingParameters;
|
||||
$message = sprintf('Some mandatory parameters are missing ("%s") to generate a URL for route "%s".', implode('", "', $missingParameters), $routeName);
|
||||
$message = \sprintf('Some mandatory parameters are missing ("%s") to generate a URL for route "%s".', implode('", "', $missingParameters), $routeName);
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,6 @@ class RouteCircularReferenceException extends RuntimeException
|
||||
{
|
||||
public function __construct(string $routeId, array $path)
|
||||
{
|
||||
parent::__construct(sprintf('Circular reference detected for route "%s", path: "%s".', $routeId, implode(' -> ', $path)));
|
||||
parent::__construct(\sprintf('Circular reference detected for route "%s", path: "%s".', $routeId, implode(' -> ', $path)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ class CompiledUrlGenerator extends UrlGenerator
|
||||
}
|
||||
|
||||
if (!isset($this->compiledRoutes[$name])) {
|
||||
throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name));
|
||||
throw new RouteNotFoundException(\sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name));
|
||||
}
|
||||
|
||||
[$variables, $defaults, $requirements, $tokens, $hostTokens, $requiredSchemes, $deprecations] = $this->compiledRoutes[$name] + [6 => []];
|
||||
|
||||
@@ -69,7 +69,7 @@ class CompiledUrlGeneratorDumper extends GeneratorDumper
|
||||
}
|
||||
|
||||
if (null === $target = $routes->get($currentId)) {
|
||||
throw new RouteNotFoundException(sprintf('Target route "%s" for alias "%s" does not exist.', $currentId, $name));
|
||||
throw new RouteNotFoundException(\sprintf('Target route "%s" for alias "%s" does not exist.', $currentId, $name));
|
||||
}
|
||||
|
||||
$compiledTarget = $target->compile();
|
||||
@@ -109,11 +109,11 @@ EOF;
|
||||
{
|
||||
$routes = '';
|
||||
foreach ($this->getCompiledRoutes() as $name => $properties) {
|
||||
$routes .= sprintf("\n '%s' => %s,", $name, CompiledUrlMatcherDumper::export($properties));
|
||||
$routes .= \sprintf("\n '%s' => %s,", $name, CompiledUrlMatcherDumper::export($properties));
|
||||
}
|
||||
|
||||
foreach ($this->getCompiledAliases() as $alias => $properties) {
|
||||
$routes .= sprintf("\n '%s' => %s,", $alias, CompiledUrlMatcherDumper::export($properties));
|
||||
$routes .= \sprintf("\n '%s' => %s,", $alias, CompiledUrlMatcherDumper::export($properties));
|
||||
}
|
||||
|
||||
return $routes;
|
||||
|
||||
+2
-2
@@ -115,7 +115,7 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt
|
||||
}
|
||||
|
||||
if (null === $route ??= $this->routes->get($name)) {
|
||||
throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name));
|
||||
throw new RouteNotFoundException(\sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name));
|
||||
}
|
||||
|
||||
// the Route has a cache of its own and is not recompiled as long as it does not get modified
|
||||
@@ -266,7 +266,7 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt
|
||||
if ($vars = get_object_vars($v)) {
|
||||
array_walk_recursive($vars, $caster);
|
||||
$v = $vars;
|
||||
} elseif (method_exists($v, '__toString')) {
|
||||
} elseif ($v instanceof \Stringable) {
|
||||
$v = (string) $v;
|
||||
}
|
||||
}
|
||||
|
||||
+76
-55
@@ -14,7 +14,7 @@ namespace Symfony\Component\Routing\Loader;
|
||||
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\Route as RouteAttribute;
|
||||
use Symfony\Component\Routing\Exception\LogicException;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
@@ -53,7 +53,11 @@ use Symfony\Component\Routing\RouteCollection;
|
||||
*/
|
||||
abstract class AttributeClassLoader implements LoaderInterface
|
||||
{
|
||||
protected string $routeAnnotationClass = RouteAnnotation::class;
|
||||
/**
|
||||
* @deprecated since Symfony 7.2, use "setRouteAttributeClass()" instead.
|
||||
*/
|
||||
protected string $routeAnnotationClass = RouteAttribute::class;
|
||||
private string $routeAttributeClass = RouteAttribute::class;
|
||||
protected int $defaultRouteIndex = 0;
|
||||
|
||||
public function __construct(
|
||||
@@ -62,11 +66,24 @@ abstract class AttributeClassLoader implements LoaderInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since Symfony 7.2, use "setRouteAttributeClass(string $class)" instead
|
||||
*
|
||||
* Sets the annotation class to read route properties from.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,12 +92,12 @@ 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()));
|
||||
}
|
||||
|
||||
$globals = $this->getGlobals($class);
|
||||
@@ -93,8 +110,8 @@ abstract class AttributeClassLoader implements LoaderInterface
|
||||
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);
|
||||
foreach ($this->getAttributes($method) as $attr) {
|
||||
$this->addRoute($collection, $attr, $globals, $class, $method);
|
||||
if ('__invoke' === $method->name) {
|
||||
$fqcnAlias = true;
|
||||
}
|
||||
@@ -102,15 +119,15 @@ abstract class AttributeClassLoader implements LoaderInterface
|
||||
|
||||
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)) {
|
||||
if ($newRouteName !== $aliasName = \sprintf('%s::%s', $class->name, $method->name)) {
|
||||
$collection->addAlias($aliasName, $newRouteName);
|
||||
}
|
||||
}
|
||||
}
|
||||
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 ($this->getAttributes($class) as $attr) {
|
||||
$this->addRoute($collection, $attr, $globals, $class, $class->getMethod('__invoke'));
|
||||
$fqcnAlias = true;
|
||||
}
|
||||
}
|
||||
@@ -120,7 +137,7 @@ abstract class AttributeClassLoader implements LoaderInterface
|
||||
$collection->addAlias($class->name, $invokeRouteName);
|
||||
}
|
||||
|
||||
if ($invokeRouteName !== $aliasName = sprintf('%s::__invoke', $class->name)) {
|
||||
if ($invokeRouteName !== $aliasName = \sprintf('%s::__invoke', $class->name)) {
|
||||
$collection->addAlias($aliasName, $invokeRouteName);
|
||||
}
|
||||
}
|
||||
@@ -129,36 +146,36 @@ abstract class AttributeClassLoader implements LoaderInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RouteAnnotation $annot or an object that exposes a similar interface
|
||||
* @param RouteAttribute $attr or an object that exposes a similar interface
|
||||
*/
|
||||
protected function addRoute(RouteCollection $collection, object $annot, array $globals, \ReflectionClass $class, \ReflectionMethod $method): void
|
||||
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 = [];
|
||||
|
||||
@@ -168,11 +185,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;
|
||||
@@ -191,7 +208,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) {
|
||||
@@ -204,7 +221,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));
|
||||
@@ -227,7 +244,7 @@ abstract class AttributeClassLoader implements LoaderInterface
|
||||
|
||||
public function getResolver(): LoaderResolverInterface
|
||||
{
|
||||
throw new LogicException(sprintf('The "%s()" method must not be called.', __METHOD__));
|
||||
throw new LogicException(\sprintf('The "%s()" method must not be called.', __METHOD__));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -254,53 +271,54 @@ abstract class AttributeClassLoader implements LoaderInterface
|
||||
{
|
||||
$globals = $this->resetGlobals();
|
||||
|
||||
// to be replaced in Symfony 8.0 by $this->routeAttributeClass
|
||||
if ($attribute = $class->getAttributes($this->routeAnnotationClass, \ReflectionAttribute::IS_INSTANCEOF)[0] ?? null) {
|
||||
$annot = $attribute->newInstance();
|
||||
$attr = $attribute->newInstance();
|
||||
|
||||
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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -332,15 +350,18 @@ abstract class AttributeClassLoader implements LoaderInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @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();
|
||||
}
|
||||
|
||||
+1
-1
@@ -76,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 forget 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];
|
||||
|
||||
@@ -79,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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
+3
-7
@@ -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
|
||||
|
||||
+15
-15
@@ -88,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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ class XmlFileLoader extends FileLoader
|
||||
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')) {
|
||||
@@ -124,11 +124,11 @@ 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'));
|
||||
@@ -161,7 +161,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');
|
||||
@@ -174,7 +174,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 = [];
|
||||
@@ -288,15 +288,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;
|
||||
@@ -312,9 +312,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);
|
||||
@@ -410,7 +410,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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,7 +438,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;
|
||||
@@ -449,10 +449,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 [
|
||||
|
||||
+15
-15
@@ -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) {
|
||||
@@ -135,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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +244,7 @@ class YamlFileLoader extends FileLoader
|
||||
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);
|
||||
@@ -252,22 +252,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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,16 +279,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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ EOF;
|
||||
|
||||
$code .= '[ // $staticRoutes'."\n";
|
||||
foreach ($staticRoutes as $path => $routes) {
|
||||
$code .= sprintf(" %s => [\n", self::export($path));
|
||||
$code .= \sprintf(" %s => [\n", self::export($path));
|
||||
foreach ($routes as $route) {
|
||||
$code .= vsprintf(" [%s, %s, %s, %s, %s, %s, %s],\n", array_map([__CLASS__, 'export'], $route));
|
||||
}
|
||||
@@ -142,11 +142,11 @@ EOF;
|
||||
}
|
||||
$code .= "],\n";
|
||||
|
||||
$code .= sprintf("[ // \$regexpList%s\n],\n", $regexpCode);
|
||||
$code .= \sprintf("[ // \$regexpList%s\n],\n", $regexpCode);
|
||||
|
||||
$code .= '[ // $dynamicRoutes'."\n";
|
||||
foreach ($dynamicRoutes as $path => $routes) {
|
||||
$code .= sprintf(" %s => [\n", self::export($path));
|
||||
$code .= \sprintf(" %s => [\n", self::export($path));
|
||||
foreach ($routes as $route) {
|
||||
$code .= vsprintf(" [%s, %s, %s, %s, %s, %s, %s],\n", array_map([__CLASS__, 'export'], $route));
|
||||
}
|
||||
@@ -399,7 +399,7 @@ EOF;
|
||||
|
||||
$state->mark += 3 + $state->markTail + \strlen($regex) - $prefixLen;
|
||||
$state->markTail = 2 + \strlen($state->mark);
|
||||
$rx = sprintf('|%s(*:%s)', substr($regex, $prefixLen), $state->mark);
|
||||
$rx = \sprintf('|%s(*:%s)', substr($regex, $prefixLen), $state->mark);
|
||||
$code .= "\n .".self::export($rx);
|
||||
$state->regex .= $rx;
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ trait CompiledUrlMatcherTrait
|
||||
throw new MethodNotAllowedException(array_keys($allow));
|
||||
}
|
||||
if (!$this instanceof RedirectableUrlMatcherInterface) {
|
||||
throw new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo));
|
||||
throw new ResourceNotFoundException(\sprintf('No routes found for "%s".', $pathinfo));
|
||||
}
|
||||
if (!\in_array($this->context->getMethod(), ['HEAD', 'GET'], true)) {
|
||||
// no-op
|
||||
@@ -67,7 +67,7 @@ trait CompiledUrlMatcherTrait
|
||||
}
|
||||
}
|
||||
|
||||
throw new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo));
|
||||
throw new ResourceNotFoundException(\sprintf('No routes found for "%s".', $pathinfo));
|
||||
}
|
||||
|
||||
private function doMatch(string $pathinfo, array &$allow = [], array &$allowSchemes = []): array
|
||||
|
||||
@@ -23,8 +23,6 @@ use Symfony\Component\Routing\RouteCollection;
|
||||
*/
|
||||
class StaticPrefixCollection
|
||||
{
|
||||
private string $prefix;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
@@ -40,9 +38,9 @@ class StaticPrefixCollection
|
||||
*/
|
||||
private array $items = [];
|
||||
|
||||
public function __construct(string $prefix = '/')
|
||||
{
|
||||
$this->prefix = $prefix;
|
||||
public function __construct(
|
||||
private string $prefix = '/',
|
||||
) {
|
||||
}
|
||||
|
||||
public function getPrefix(): string
|
||||
|
||||
@@ -34,7 +34,7 @@ class ExpressionLanguageProvider implements ExpressionFunctionProviderInterface
|
||||
foreach ($this->functions->getProvidedServices() as $function => $type) {
|
||||
$functions[] = new ExpressionFunction(
|
||||
$function,
|
||||
static fn (...$args) => sprintf('($context->getParameter(\'_functions\')->get(%s)(%s))', var_export($function, true), implode(', ', $args)),
|
||||
static fn (...$args) => \sprintf('($context->getParameter(\'_functions\')->get(%s)(%s))', var_export($function, true), implode(', ', $args)),
|
||||
fn ($values, ...$args) => $values['context']->getParameter('_functions')->get($function)(...$args)
|
||||
);
|
||||
}
|
||||
|
||||
+8
-8
@@ -66,7 +66,7 @@ class TraceableUrlMatcher extends UrlMatcher
|
||||
|
||||
// check the static prefix of the URL first. Only use the more expensive preg_match when it matches
|
||||
if ('' !== $staticPrefix && !str_starts_with($trimmedPathinfo, $staticPrefix)) {
|
||||
$this->addTrace(sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route);
|
||||
$this->addTrace(\sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route);
|
||||
continue;
|
||||
}
|
||||
$regex = $compiledRoute->getRegex();
|
||||
@@ -80,7 +80,7 @@ class TraceableUrlMatcher extends UrlMatcher
|
||||
$r = new Route($route->getPath(), $route->getDefaults(), [], $route->getOptions());
|
||||
$cr = $r->compile();
|
||||
if (!preg_match($cr->getRegex(), $pathinfo)) {
|
||||
$this->addTrace(sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route);
|
||||
$this->addTrace(\sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route);
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -90,7 +90,7 @@ class TraceableUrlMatcher extends UrlMatcher
|
||||
$cr = $r->compile();
|
||||
|
||||
if (\in_array($n, $cr->getVariables()) && !preg_match($cr->getRegex(), $pathinfo)) {
|
||||
$this->addTrace(sprintf('Requirement for "%s" does not match (%s)', $n, $regex), self::ROUTE_ALMOST_MATCHES, $name, $route);
|
||||
$this->addTrace(\sprintf('Requirement for "%s" does not match (%s)', $n, $regex), self::ROUTE_ALMOST_MATCHES, $name, $route);
|
||||
|
||||
continue 2;
|
||||
}
|
||||
@@ -111,7 +111,7 @@ class TraceableUrlMatcher extends UrlMatcher
|
||||
|
||||
$hostMatches = [];
|
||||
if ($compiledRoute->getHostRegex() && !preg_match($compiledRoute->getHostRegex(), $this->context->getHost(), $hostMatches)) {
|
||||
$this->addTrace(sprintf('Host "%s" does not match the requirement ("%s")', $this->context->getHost(), $route->getHost()), self::ROUTE_ALMOST_MATCHES, $name, $route);
|
||||
$this->addTrace(\sprintf('Host "%s" does not match the requirement ("%s")', $this->context->getHost(), $route->getHost()), self::ROUTE_ALMOST_MATCHES, $name, $route);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ class TraceableUrlMatcher extends UrlMatcher
|
||||
$status = $this->handleRouteRequirements($pathinfo, $name, $route, $attributes);
|
||||
|
||||
if (self::REQUIREMENT_MISMATCH === $status[0]) {
|
||||
$this->addTrace(sprintf('Condition "%s" does not evaluate to "true"', $route->getCondition()), self::ROUTE_ALMOST_MATCHES, $name, $route);
|
||||
$this->addTrace(\sprintf('Condition "%s" does not evaluate to "true"', $route->getCondition()), self::ROUTE_ALMOST_MATCHES, $name, $route);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -130,19 +130,19 @@ class TraceableUrlMatcher extends UrlMatcher
|
||||
|
||||
return $this->allow = $this->allowSchemes = [];
|
||||
}
|
||||
$this->addTrace(sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route);
|
||||
$this->addTrace(\sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($route->getSchemes() && !$route->hasScheme($this->context->getScheme())) {
|
||||
$this->allowSchemes = array_merge($this->allowSchemes, $route->getSchemes());
|
||||
$this->addTrace(sprintf('Scheme "%s" does not match any of the required schemes (%s)', $this->context->getScheme(), implode(', ', $route->getSchemes())), self::ROUTE_ALMOST_MATCHES, $name, $route);
|
||||
$this->addTrace(\sprintf('Scheme "%s" does not match any of the required schemes (%s)', $this->context->getScheme(), implode(', ', $route->getSchemes())), self::ROUTE_ALMOST_MATCHES, $name, $route);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($requiredMethods && !\in_array($method, $requiredMethods, true)) {
|
||||
$this->allow = array_merge($this->allow, $requiredMethods);
|
||||
$this->addTrace(sprintf('Method "%s" does not match any of the required methods (%s)', $this->context->getMethod(), implode(', ', $requiredMethods)), self::ROUTE_ALMOST_MATCHES, $name, $route);
|
||||
$this->addTrace(\sprintf('Method "%s" does not match any of the required methods (%s)', $this->context->getMethod(), implode(', ', $requiredMethods)), self::ROUTE_ALMOST_MATCHES, $name, $route);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -79,7 +79,7 @@ class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface
|
||||
throw new NoConfigurationException();
|
||||
}
|
||||
|
||||
throw 0 < \count($this->allow) ? new MethodNotAllowedException(array_unique($this->allow)) : new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo));
|
||||
throw 0 < \count($this->allow) ? new MethodNotAllowedException(array_unique($this->allow)) : new ResourceNotFoundException(\sprintf('No routes found for "%s".', $pathinfo));
|
||||
}
|
||||
|
||||
public function matchRequest(Request $request): array
|
||||
|
||||
+7
@@ -47,6 +47,13 @@ class RequestContext
|
||||
|
||||
public static function fromUri(string $uri, string $host = 'localhost', string $scheme = 'http', int $httpPort = 80, int $httpsPort = 443): self
|
||||
{
|
||||
if (false !== ($i = strpos($uri, '\\')) && $i < strcspn($uri, '?#')) {
|
||||
$uri = '';
|
||||
}
|
||||
if ('' !== $uri && (\ord($uri[0]) <= 32 || \ord($uri[-1]) <= 32 || \strlen($uri) !== strcspn($uri, "\r\n\t"))) {
|
||||
$uri = '';
|
||||
}
|
||||
|
||||
$uri = parse_url($uri);
|
||||
$scheme = $uri['scheme'] ?? $scheme;
|
||||
$host = $uri['host'] ?? $host;
|
||||
|
||||
+3
-3
@@ -26,7 +26,7 @@ final class EnumRequirement implements \Stringable
|
||||
{
|
||||
if (\is_string($cases)) {
|
||||
if (!is_subclass_of($cases, \BackedEnum::class, true)) {
|
||||
throw new InvalidArgumentException(sprintf('"%s" is not a "BackedEnum" class.', $cases));
|
||||
throw new InvalidArgumentException(\sprintf('"%s" is not a "BackedEnum" class.', $cases));
|
||||
}
|
||||
|
||||
$cases = $cases::cases();
|
||||
@@ -35,13 +35,13 @@ final class EnumRequirement implements \Stringable
|
||||
|
||||
foreach ($cases as $case) {
|
||||
if (!$case instanceof \BackedEnum) {
|
||||
throw new InvalidArgumentException(sprintf('Case must be a "BackedEnum" instance, "%s" given.', get_debug_type($case)));
|
||||
throw new InvalidArgumentException(\sprintf('Case must be a "BackedEnum" instance, "%s" given.', get_debug_type($case)));
|
||||
}
|
||||
|
||||
$class ??= $case::class;
|
||||
|
||||
if (!$case instanceof $class) {
|
||||
throw new InvalidArgumentException(sprintf('"%s::%s" is not a case of "%s".', get_debug_type($case), $case->name, $class));
|
||||
throw new InvalidArgumentException(\sprintf('"%s::%s" is not a case of "%s".', get_debug_type($case), $case->name, $class));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -23,7 +23,8 @@ enum Requirement
|
||||
public const POSITIVE_INT = '[1-9][0-9]*';
|
||||
public const UID_BASE32 = '[0-9A-HJKMNP-TV-Z]{26}';
|
||||
public const UID_BASE58 = '[1-9A-HJ-NP-Za-km-z]{22}';
|
||||
public const UID_RFC4122 = '[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}'; // RFC 9562 obsoleted RFC 4122 but the format is the same
|
||||
public const UID_RFC4122 = '[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}';
|
||||
public const UID_RFC9562 = self::UID_RFC4122;
|
||||
public const ULID = '[0-7][0-9A-HJKMNP-TV-Z]{25}';
|
||||
public const UUID = '[0-9a-f]{8}-[0-9a-f]{4}-[13-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}';
|
||||
public const UUID_V1 = '[0-9a-f]{8}-[0-9a-f]{4}-1[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}';
|
||||
|
||||
Vendored
+1
-1
@@ -456,7 +456,7 @@ class Route implements \Serializable
|
||||
}
|
||||
|
||||
if ('' === $regex) {
|
||||
throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" cannot be empty.', $key));
|
||||
throw new \InvalidArgumentException(\sprintf('Routing requirement for "%s" cannot be empty.', $key));
|
||||
}
|
||||
|
||||
return $regex;
|
||||
|
||||
+1
-1
@@ -360,7 +360,7 @@ class RouteCollection implements \IteratorAggregate, \Countable
|
||||
public function addAlias(string $name, string $alias): Alias
|
||||
{
|
||||
if ($name === $alias) {
|
||||
throw new InvalidArgumentException(sprintf('Route alias "%s" can not reference itself.', $name));
|
||||
throw new InvalidArgumentException(\sprintf('Route alias "%s" can not reference itself.', $name));
|
||||
}
|
||||
|
||||
unset($this->routes[$name], $this->priorities[$name]);
|
||||
|
||||
+29
-29
@@ -75,7 +75,7 @@ class RouteCompiler implements RouteCompilerInterface
|
||||
|
||||
foreach ($pathVariables as $pathParam) {
|
||||
if ('_fragment' === $pathParam) {
|
||||
throw new \InvalidArgumentException(sprintf('Route pattern "%s" cannot contain "_fragment" as a path parameter.', $route->getPath()));
|
||||
throw new \InvalidArgumentException(\sprintf('Route pattern "%s" cannot contain "_fragment" as a path parameter.', $route->getPath()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,10 +107,10 @@ class RouteCompiler implements RouteCompilerInterface
|
||||
$needsUtf8 = $route->getOption('utf8');
|
||||
|
||||
if (!$needsUtf8 && $useUtf8 && preg_match('/[\x80-\xFF]/', $pattern)) {
|
||||
throw new \LogicException(sprintf('Cannot use UTF-8 route patterns without setting the "utf8" option for route "%s".', $route->getPath()));
|
||||
throw new \LogicException(\sprintf('Cannot use UTF-8 route patterns without setting the "utf8" option for route "%s".', $route->getPath()));
|
||||
}
|
||||
if (!$useUtf8 && $needsUtf8) {
|
||||
throw new \LogicException(sprintf('Cannot mix UTF-8 requirements with non-UTF-8 pattern "%s".', $pattern));
|
||||
throw new \LogicException(\sprintf('Cannot mix UTF-8 requirements with non-UTF-8 pattern "%s".', $pattern));
|
||||
}
|
||||
|
||||
// Match all variables enclosed in "{}" and iterate over them. But we only want to match the innermost variable
|
||||
@@ -136,14 +136,14 @@ class RouteCompiler implements RouteCompilerInterface
|
||||
// A PCRE subpattern name must start with a non-digit. Also a PHP variable cannot start with a digit so the
|
||||
// variable would not be usable as a Controller action argument.
|
||||
if (preg_match('/^\d/', $varName)) {
|
||||
throw new \DomainException(sprintf('Variable name "%s" cannot start with a digit in route pattern "%s". Please use a different name.', $varName, $pattern));
|
||||
throw new \DomainException(\sprintf('Variable name "%s" cannot start with a digit in route pattern "%s". Please use a different name.', $varName, $pattern));
|
||||
}
|
||||
if (\in_array($varName, $variables)) {
|
||||
throw new \LogicException(sprintf('Route pattern "%s" cannot reference variable name "%s" more than once.', $pattern, $varName));
|
||||
throw new \LogicException(\sprintf('Route pattern "%s" cannot reference variable name "%s" more than once.', $pattern, $varName));
|
||||
}
|
||||
|
||||
if (\strlen($varName) > self::VARIABLE_MAXIMUM_LENGTH) {
|
||||
throw new \DomainException(sprintf('Variable name "%s" cannot be longer than %d characters in route pattern "%s". Please use a shorter name.', $varName, self::VARIABLE_MAXIMUM_LENGTH, $pattern));
|
||||
throw new \DomainException(\sprintf('Variable name "%s" cannot be longer than %d characters in route pattern "%s". Please use a shorter name.', $varName, self::VARIABLE_MAXIMUM_LENGTH, $pattern));
|
||||
}
|
||||
|
||||
if ($isSeparator && $precedingText !== $precedingChar) {
|
||||
@@ -154,7 +154,7 @@ class RouteCompiler implements RouteCompilerInterface
|
||||
|
||||
$regexp = $route->getRequirement($varName);
|
||||
if (null === $regexp) {
|
||||
$followingPattern = (string) substr($pattern, $pos);
|
||||
$followingPattern = substr($pattern, $pos);
|
||||
// Find the next static character after the variable that functions as a separator. By default, this separator and '/'
|
||||
// are disallowed for the variable. This default requirement makes sure that optional variables can be matched at all
|
||||
// and that the generating-matching-combination of URLs unambiguous, i.e. the params used for generating the URL are
|
||||
@@ -163,7 +163,7 @@ class RouteCompiler implements RouteCompilerInterface
|
||||
// Also even if {_format} was not optional the requirement prevents that {page} matches something that was originally
|
||||
// part of {_format} when generating the URL, e.g. _format = 'mobile.html'.
|
||||
$nextSeparator = self::findNextSeparator($followingPattern, $useUtf8);
|
||||
$regexp = sprintf(
|
||||
$regexp = \sprintf(
|
||||
'[^%s%s]+',
|
||||
preg_quote($defaultSeparator),
|
||||
$defaultSeparator !== $nextSeparator && '' !== $nextSeparator ? preg_quote($nextSeparator) : ''
|
||||
@@ -180,10 +180,10 @@ class RouteCompiler implements RouteCompilerInterface
|
||||
if (!preg_match('//u', $regexp)) {
|
||||
$useUtf8 = false;
|
||||
} elseif (!$needsUtf8 && preg_match('/[\x80-\xFF]|(?<!\\\\)\\\\(?:\\\\\\\\)*+(?-i:X|[pP][\{CLMNPSZ]|x\{[A-Fa-f0-9]{3})/', $regexp)) {
|
||||
throw new \LogicException(sprintf('Cannot use UTF-8 route requirements without setting the "utf8" option for variable "%s" in pattern "%s".', $varName, $pattern));
|
||||
throw new \LogicException(\sprintf('Cannot use UTF-8 route requirements without setting the "utf8" option for variable "%s" in pattern "%s".', $varName, $pattern));
|
||||
}
|
||||
if (!$useUtf8 && $needsUtf8) {
|
||||
throw new \LogicException(sprintf('Cannot mix UTF-8 requirement with non-UTF-8 charset for variable "%s" in pattern "%s".', $varName, $pattern));
|
||||
throw new \LogicException(\sprintf('Cannot mix UTF-8 requirement with non-UTF-8 charset for variable "%s" in pattern "%s".', $varName, $pattern));
|
||||
}
|
||||
$regexp = self::transformCapturingGroupsToNonCapturings($regexp);
|
||||
}
|
||||
@@ -292,28 +292,28 @@ class RouteCompiler implements RouteCompilerInterface
|
||||
if ('text' === $token[0]) {
|
||||
// Text tokens
|
||||
return preg_quote($token[1]);
|
||||
} else {
|
||||
// Variable tokens
|
||||
if (0 === $index && 0 === $firstOptional) {
|
||||
// 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 {
|
||||
$regexp = sprintf('%s(?P<%s>%s)', preg_quote($token[1]), $token[3], $token[2]);
|
||||
if ($index >= $firstOptional) {
|
||||
// Enclose each optional token in a subpattern to make it optional.
|
||||
// "?:" means it is non-capturing, i.e. the portion of the subject string that
|
||||
// matched the optional subpattern is not passed back.
|
||||
$regexp = "(?:$regexp";
|
||||
$nbTokens = \count($tokens);
|
||||
if ($nbTokens - 1 == $index) {
|
||||
// Close the optional subpatterns
|
||||
$regexp .= str_repeat(')?', $nbTokens - $firstOptional - (0 === $firstOptional ? 1 : 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $regexp;
|
||||
// Variable tokens
|
||||
if (0 === $index && 0 === $firstOptional) {
|
||||
// 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]);
|
||||
}
|
||||
|
||||
$regexp = \sprintf('%s(?P<%s>%s)', preg_quote($token[1]), $token[3], $token[2]);
|
||||
if ($index >= $firstOptional) {
|
||||
// Enclose each optional token in a subpattern to make it optional.
|
||||
// "?:" means it is non-capturing, i.e. the portion of the subject string that
|
||||
// matched the optional subpattern is not passed back.
|
||||
$regexp = "(?:$regexp";
|
||||
$nbTokens = \count($tokens);
|
||||
if ($nbTokens - 1 == $index) {
|
||||
// Close the optional subpatterns
|
||||
$regexp .= str_repeat(')?', $nbTokens - $firstOptional - (0 === $firstOptional ? 1 : 0));
|
||||
}
|
||||
}
|
||||
|
||||
return $regexp;
|
||||
}
|
||||
|
||||
private static function transformCapturingGroupsToNonCapturings(string $regexp): string
|
||||
|
||||
Vendored
+11
-13
@@ -40,12 +40,8 @@ class Router implements RouterInterface, RequestMatcherInterface
|
||||
protected UrlMatcherInterface|RequestMatcherInterface $matcher;
|
||||
protected UrlGeneratorInterface $generator;
|
||||
protected RequestContext $context;
|
||||
protected LoaderInterface $loader;
|
||||
protected RouteCollection $collection;
|
||||
protected mixed $resource;
|
||||
protected array $options = [];
|
||||
protected ?LoggerInterface $logger;
|
||||
protected ?string $defaultLocale;
|
||||
|
||||
private ConfigCacheFactoryInterface $configCacheFactory;
|
||||
|
||||
@@ -56,14 +52,16 @@ class Router implements RouterInterface, RequestMatcherInterface
|
||||
|
||||
private static ?array $cache = [];
|
||||
|
||||
public function __construct(LoaderInterface $loader, mixed $resource, array $options = [], ?RequestContext $context = null, ?LoggerInterface $logger = null, ?string $defaultLocale = null)
|
||||
{
|
||||
$this->loader = $loader;
|
||||
$this->resource = $resource;
|
||||
$this->logger = $logger;
|
||||
public function __construct(
|
||||
protected LoaderInterface $loader,
|
||||
protected mixed $resource,
|
||||
array $options = [],
|
||||
?RequestContext $context = null,
|
||||
protected ?LoggerInterface $logger = null,
|
||||
protected ?string $defaultLocale = null,
|
||||
) {
|
||||
$this->context = $context ?? new RequestContext();
|
||||
$this->setOptions($options);
|
||||
$this->defaultLocale = $defaultLocale;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,7 +105,7 @@ class Router implements RouterInterface, RequestMatcherInterface
|
||||
}
|
||||
|
||||
if ($invalid) {
|
||||
throw new \InvalidArgumentException(sprintf('The Router does not support the following options: "%s".', implode('", "', $invalid)));
|
||||
throw new \InvalidArgumentException(\sprintf('The Router does not support the following options: "%s".', implode('", "', $invalid)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +117,7 @@ class Router implements RouterInterface, RequestMatcherInterface
|
||||
public function setOption(string $key, mixed $value): void
|
||||
{
|
||||
if (!\array_key_exists($key, $this->options)) {
|
||||
throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key));
|
||||
throw new \InvalidArgumentException(\sprintf('The Router does not support the "%s" option.', $key));
|
||||
}
|
||||
|
||||
$this->options[$key] = $value;
|
||||
@@ -133,7 +131,7 @@ class Router implements RouterInterface, RequestMatcherInterface
|
||||
public function getOption(string $key): mixed
|
||||
{
|
||||
if (!\array_key_exists($key, $this->options)) {
|
||||
throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key));
|
||||
throw new \InvalidArgumentException(\sprintf('The Router does not support the "%s" option.', $key));
|
||||
}
|
||||
|
||||
return $this->options[$key];
|
||||
|
||||
Reference in New Issue
Block a user