first commit
This commit is contained in:
25
vendor/symfony/routing/Loader/AnnotationClassLoader.php
vendored
Normal file
25
vendor/symfony/routing/Loader/AnnotationClassLoader.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Routing\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
|
||||
{
|
||||
}
|
||||
}
|
25
vendor/symfony/routing/Loader/AnnotationDirectoryLoader.php
vendored
Normal file
25
vendor/symfony/routing/Loader/AnnotationDirectoryLoader.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Routing\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
|
||||
{
|
||||
}
|
||||
}
|
25
vendor/symfony/routing/Loader/AnnotationFileLoader.php
vendored
Normal file
25
vendor/symfony/routing/Loader/AnnotationFileLoader.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Routing\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
|
||||
{
|
||||
}
|
||||
}
|
431
vendor/symfony/routing/Loader/AttributeClassLoader.php
vendored
Normal file
431
vendor/symfony/routing/Loader/AttributeClassLoader.php
vendored
Normal file
@ -0,0 +1,431 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Routing\Loader;
|
||||
|
||||
use Doctrine\Common\Annotations\Reader;
|
||||
use Symfony\Component\Config\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\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* AttributeClassLoader loads routing information from a PHP class and its methods.
|
||||
*
|
||||
* You need to define an implementation for the configureRoute() method. Most of the
|
||||
* time, this method should define some PHP callable to be called for the route
|
||||
* (a controller in MVC speak).
|
||||
*
|
||||
* The #[Route] attribute can be set on the class (for global parameters),
|
||||
* and on each method.
|
||||
*
|
||||
* The #[Route] attribute main value is the route path. The attribute also
|
||||
* recognizes several parameters: requirements, options, defaults, schemes,
|
||||
* methods, host, and name. The name parameter is mandatory.
|
||||
* Here is an example of how you should be able to use it:
|
||||
*
|
||||
* #[Route('/Blog')]
|
||||
* class Blog
|
||||
* {
|
||||
* #[Route('/', name: 'blog_index')]
|
||||
* public function index()
|
||||
* {
|
||||
* }
|
||||
* #[Route('/{id}', name: 'blog_post', requirements: ["id" => '\d+'])]
|
||||
* public function show()
|
||||
* {
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Alexander M. Turek <me@derrabus.de>
|
||||
* @author Alexandre Daubois <alex.daubois@gmail.com>
|
||||
*/
|
||||
abstract class AttributeClassLoader implements LoaderInterface
|
||||
{
|
||||
/**
|
||||
* @var Reader|null
|
||||
*
|
||||
* @deprecated in Symfony 6.4, this property will be removed in Symfony 7.
|
||||
*/
|
||||
protected $reader;
|
||||
|
||||
/**
|
||||
* @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)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the annotation class to read route properties from.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setRouteAnnotationClass(string $class)
|
||||
{
|
||||
$this->routeAnnotationClass = $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException When route can't be parsed
|
||||
*/
|
||||
public function load(mixed $class, ?string $type = null): RouteCollection
|
||||
{
|
||||
if (!class_exists($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()));
|
||||
}
|
||||
|
||||
$this->hasDeprecatedAnnotations = 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 (0 === $collection->count() && $class->hasMethod('__invoke')) {
|
||||
$globals = $this->resetGlobals();
|
||||
foreach ($this->getAnnotations($class) as $annot) {
|
||||
$this->addRoute($collection, $annot, $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);
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
} finally {
|
||||
$this->hasDeprecatedAnnotations = false;
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RouteAnnotation $annot or an object that exposes a similar interface
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function addRoute(RouteCollection $collection, object $annot, array $globals, \ReflectionClass $class, \ReflectionMethod $method)
|
||||
{
|
||||
if ($annot->getEnv() && $annot->getEnv() !== $this->env) {
|
||||
return;
|
||||
}
|
||||
|
||||
$name = $annot->getName() ?? $this->getDefaultRouteName($class, $method);
|
||||
$name = $globals['name'].$name;
|
||||
|
||||
$requirements = $annot->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()));
|
||||
}
|
||||
}
|
||||
|
||||
$defaults = array_replace($globals['defaults'], $annot->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()));
|
||||
|
||||
$host = $annot->getHost() ?? $globals['host'];
|
||||
$condition = $annot->getCondition() ?? $globals['condition'];
|
||||
$priority = $annot->getPriority() ?? $globals['priority'];
|
||||
|
||||
$path = $annot->getLocalizedPaths() ?: $annot->getPath();
|
||||
$prefix = $globals['localized_paths'] ?: $globals['path'];
|
||||
$paths = [];
|
||||
|
||||
if (\is_array($path)) {
|
||||
if (!\is_array($prefix)) {
|
||||
foreach ($path as $locale => $localePath) {
|
||||
$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))));
|
||||
} 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));
|
||||
}
|
||||
|
||||
$paths[$locale] = $prefix[$locale].$localePath;
|
||||
}
|
||||
}
|
||||
} elseif (\is_array($prefix)) {
|
||||
foreach ($prefix as $locale => $localePrefix) {
|
||||
$paths[$locale] = $localePrefix.$path;
|
||||
}
|
||||
} else {
|
||||
$paths[] = $prefix.$path;
|
||||
}
|
||||
|
||||
foreach ($method->getParameters() as $param) {
|
||||
if (isset($defaults[$param->name]) || !$param->isDefaultValueAvailable()) {
|
||||
continue;
|
||||
}
|
||||
foreach ($paths as $locale => $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) {
|
||||
$defaults[$param->name] = $defaultValue->value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($paths as $locale => $path) {
|
||||
$route = $this->createRoute($path, $defaults, $requirements, $options, $host, $schemes, $methods, $condition);
|
||||
$this->configureRoute($route, $class, $method, $annot);
|
||||
if (0 !== $locale) {
|
||||
$route->setDefault('_locale', $locale);
|
||||
$route->setRequirement('_locale', preg_quote($locale));
|
||||
$route->setDefault('_canonical_route', $name);
|
||||
$collection->add($name.'.'.$locale, $route, $priority);
|
||||
} else {
|
||||
$collection->add($name, $route, $priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
public function setResolver(LoaderResolverInterface $resolver): void
|
||||
{
|
||||
}
|
||||
|
||||
public function getResolver(): LoaderResolverInterface
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default route name for a class method.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getDefaultRouteName(\ReflectionClass $class, \ReflectionMethod $method)
|
||||
{
|
||||
$name = str_replace('\\', '_', $class->name).'_'.$method->name;
|
||||
$name = \function_exists('mb_strtolower') && preg_match('//u', $name) ? mb_strtolower($name, 'UTF-8') : strtolower($name);
|
||||
if ($this->defaultRouteIndex > 0) {
|
||||
$name .= '_'.$this->defaultRouteIndex;
|
||||
}
|
||||
++$this->defaultRouteIndex;
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
protected function getGlobals(\ReflectionClass $class)
|
||||
{
|
||||
$globals = $this->resetGlobals();
|
||||
|
||||
$annot = null;
|
||||
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;
|
||||
}
|
||||
|
||||
if ($annot) {
|
||||
if (null !== $annot->getName()) {
|
||||
$globals['name'] = $annot->getName();
|
||||
}
|
||||
|
||||
if (null !== $annot->getPath()) {
|
||||
$globals['path'] = $annot->getPath();
|
||||
}
|
||||
|
||||
$globals['localized_paths'] = $annot->getLocalizedPaths();
|
||||
|
||||
if (null !== $annot->getRequirements()) {
|
||||
$globals['requirements'] = $annot->getRequirements();
|
||||
}
|
||||
|
||||
if (null !== $annot->getOptions()) {
|
||||
$globals['options'] = $annot->getOptions();
|
||||
}
|
||||
|
||||
if (null !== $annot->getDefaults()) {
|
||||
$globals['defaults'] = $annot->getDefaults();
|
||||
}
|
||||
|
||||
if (null !== $annot->getSchemes()) {
|
||||
$globals['schemes'] = $annot->getSchemes();
|
||||
}
|
||||
|
||||
if (null !== $annot->getMethods()) {
|
||||
$globals['methods'] = $annot->getMethods();
|
||||
}
|
||||
|
||||
if (null !== $annot->getHost()) {
|
||||
$globals['host'] = $annot->getHost();
|
||||
}
|
||||
|
||||
if (null !== $annot->getCondition()) {
|
||||
$globals['condition'] = $annot->getCondition();
|
||||
}
|
||||
|
||||
$globals['priority'] = $annot->getPriority() ?? 0;
|
||||
$globals['env'] = $annot->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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $globals;
|
||||
}
|
||||
|
||||
private function resetGlobals(): array
|
||||
{
|
||||
return [
|
||||
'path' => null,
|
||||
'localized_paths' => [],
|
||||
'requirements' => [],
|
||||
'options' => [],
|
||||
'defaults' => [],
|
||||
'schemes' => [],
|
||||
'methods' => [],
|
||||
'host' => '',
|
||||
'condition' => '',
|
||||
'name' => '',
|
||||
'priority' => 0,
|
||||
'env' => null,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Route
|
||||
*/
|
||||
protected function createRoute(string $path, array $defaults, array $requirements, array $options, ?string $host, array $schemes, array $methods, ?string $condition)
|
||||
{
|
||||
return new Route($path, $defaults, $requirements, $options, $host, $schemes, $methods, $condition);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, object $annot);
|
||||
|
||||
/**
|
||||
* @return iterable<int, RouteAnnotation>
|
||||
*/
|
||||
private function getAnnotations(\ReflectionClass|\ReflectionMethod $reflection): iterable
|
||||
{
|
||||
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);
|
||||
}
|
92
vendor/symfony/routing/Loader/AttributeDirectoryLoader.php
vendored
Normal file
92
vendor/symfony/routing/Loader/AttributeDirectoryLoader.php
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Routing\Loader;
|
||||
|
||||
use Symfony\Component\Config\Resource\DirectoryResource;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* AttributeDirectoryLoader loads routing information from attributes set
|
||||
* on PHP classes and methods.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Alexandre Daubois <alex.daubois@gmail.com>
|
||||
*/
|
||||
class AttributeDirectoryLoader extends AttributeFileLoader
|
||||
{
|
||||
/**
|
||||
* @throws \InvalidArgumentException When the directory does not exist or its routes cannot be parsed
|
||||
*/
|
||||
public function load(mixed $path, ?string $type = null): ?RouteCollection
|
||||
{
|
||||
if (!is_dir($dir = $this->locator->locate($path))) {
|
||||
return parent::supports($path, $type) ? parent::load($path, $type) : new RouteCollection();
|
||||
}
|
||||
|
||||
$collection = new RouteCollection();
|
||||
$collection->addResource(new DirectoryResource($dir, '/\.php$/'));
|
||||
$files = iterator_to_array(new \RecursiveIteratorIterator(
|
||||
new \RecursiveCallbackFilterIterator(
|
||||
new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS),
|
||||
fn (\SplFileInfo $current) => !str_starts_with($current->getBasename(), '.')
|
||||
),
|
||||
\RecursiveIteratorIterator::LEAVES_ONLY
|
||||
));
|
||||
usort($files, fn (\SplFileInfo $a, \SplFileInfo $b) => (string) $a > (string) $b ? 1 : -1);
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (!$file->isFile() || !str_ends_with($file->getFilename(), '.php')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($class = $this->findClass($file)) {
|
||||
$refl = new \ReflectionClass($class);
|
||||
if ($refl->isAbstract()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$collection->addCollection($this->loader->load($class, $type));
|
||||
}
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
public function supports(mixed $resource, ?string $type = null): bool
|
||||
{
|
||||
if (!\is_string($resource)) {
|
||||
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.');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return is_dir($this->locator->locate($resource));
|
||||
} catch (\Exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!class_exists(AnnotationDirectoryLoader::class, false)) {
|
||||
class_alias(AttributeDirectoryLoader::class, AnnotationDirectoryLoader::class);
|
||||
}
|
145
vendor/symfony/routing/Loader/AttributeFileLoader.php
vendored
Normal file
145
vendor/symfony/routing/Loader/AttributeFileLoader.php
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Routing\Loader;
|
||||
|
||||
use Symfony\Component\Config\FileLocatorInterface;
|
||||
use Symfony\Component\Config\Loader\FileLoader;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* AttributeFileLoader loads routing information from attributes set
|
||||
* on a PHP class and its methods.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Alexandre Daubois <alex.daubois@gmail.com>
|
||||
*/
|
||||
class AttributeFileLoader extends FileLoader
|
||||
{
|
||||
protected $loader;
|
||||
|
||||
public function __construct(FileLocatorInterface $locator, 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads from attributes from a file.
|
||||
*
|
||||
* @throws \InvalidArgumentException When the file does not exist or its routes cannot be parsed
|
||||
*/
|
||||
public function load(mixed $file, ?string $type = null): ?RouteCollection
|
||||
{
|
||||
$path = $this->locator->locate($file);
|
||||
|
||||
$collection = new RouteCollection();
|
||||
if ($class = $this->findClass($path)) {
|
||||
$refl = new \ReflectionClass($class);
|
||||
if ($refl->isAbstract()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$collection->addResource(new FileResource($path));
|
||||
$collection->addCollection($this->loader->load($class, $type));
|
||||
}
|
||||
|
||||
gc_mem_caches();
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full class name for the first class in the file.
|
||||
*/
|
||||
protected function findClass(string $file): string|false
|
||||
{
|
||||
$class = false;
|
||||
$namespace = false;
|
||||
$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));
|
||||
}
|
||||
|
||||
$nsTokens = [\T_NS_SEPARATOR => true, \T_STRING => true];
|
||||
if (\defined('T_NAME_QUALIFIED')) {
|
||||
$nsTokens[\T_NAME_QUALIFIED] = true;
|
||||
}
|
||||
for ($i = 0; isset($tokens[$i]); ++$i) {
|
||||
$token = $tokens[$i];
|
||||
if (!isset($token[1])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (true === $class && \T_STRING === $token[0]) {
|
||||
return $namespace.'\\'.$token[1];
|
||||
}
|
||||
|
||||
if (true === $namespace && isset($nsTokens[$token[0]])) {
|
||||
$namespace = $token[1];
|
||||
while (isset($tokens[++$i][1], $nsTokens[$tokens[$i][0]])) {
|
||||
$namespace .= $tokens[$i][1];
|
||||
}
|
||||
$token = $tokens[$i];
|
||||
}
|
||||
|
||||
if (\T_CLASS === $token[0]) {
|
||||
// Skip usage of ::class constant and anonymous classes
|
||||
$skipClassToken = false;
|
||||
for ($j = $i - 1; $j > 0; --$j) {
|
||||
if (!isset($tokens[$j][1])) {
|
||||
if ('(' === $tokens[$j] || ',' === $tokens[$j]) {
|
||||
$skipClassToken = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (\T_DOUBLE_COLON === $tokens[$j][0] || \T_NEW === $tokens[$j][0]) {
|
||||
$skipClassToken = true;
|
||||
break;
|
||||
} elseif (!\in_array($tokens[$j][0], [\T_WHITESPACE, \T_DOC_COMMENT, \T_COMMENT])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$skipClassToken) {
|
||||
$class = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (\T_NAMESPACE === $token[0]) {
|
||||
$namespace = true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!class_exists(AnnotationFileLoader::class, false)) {
|
||||
class_alias(AttributeFileLoader::class, AnnotationFileLoader::class);
|
||||
}
|
38
vendor/symfony/routing/Loader/ClosureLoader.php
vendored
Normal file
38
vendor/symfony/routing/Loader/ClosureLoader.php
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Routing\Loader;
|
||||
|
||||
use Symfony\Component\Config\Loader\Loader;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* ClosureLoader loads routes from a PHP closure.
|
||||
*
|
||||
* The Closure must return a RouteCollection instance.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class ClosureLoader extends Loader
|
||||
{
|
||||
/**
|
||||
* Loads a Closure.
|
||||
*/
|
||||
public function load(mixed $closure, ?string $type = null): RouteCollection
|
||||
{
|
||||
return $closure($this->env);
|
||||
}
|
||||
|
||||
public function supports(mixed $resource, ?string $type = null): bool
|
||||
{
|
||||
return $resource instanceof \Closure && (!$type || 'closure' === $type);
|
||||
}
|
||||
}
|
43
vendor/symfony/routing/Loader/Configurator/AliasConfigurator.php
vendored
Normal file
43
vendor/symfony/routing/Loader/Configurator/AliasConfigurator.php
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
<?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\Configurator;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Routing\Alias;
|
||||
|
||||
class AliasConfigurator
|
||||
{
|
||||
private Alias $alias;
|
||||
|
||||
public function __construct(Alias $alias)
|
||||
{
|
||||
$this->alias = $alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this alias is deprecated, that means it should not be called anymore.
|
||||
*
|
||||
* @param string $package The name of the composer package that is triggering the deprecation
|
||||
* @param string $version The version of the package that introduced the deprecation
|
||||
* @param string $message The deprecation message to use
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidArgumentException when the message template is invalid
|
||||
*/
|
||||
public function deprecate(string $package, string $version, string $message): static
|
||||
{
|
||||
$this->alias->setDeprecated($package, $version, $message);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
128
vendor/symfony/routing/Loader/Configurator/CollectionConfigurator.php
vendored
Normal file
128
vendor/symfony/routing/Loader/Configurator/CollectionConfigurator.php
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Routing\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class CollectionConfigurator
|
||||
{
|
||||
use Traits\AddTrait;
|
||||
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;
|
||||
$this->name = $name;
|
||||
$this->collection = new RouteCollection();
|
||||
$this->route = new Route('');
|
||||
$this->parentConfigurator = $parentConfigurator; // for GC control
|
||||
$this->parentPrefixes = $parentPrefixes;
|
||||
}
|
||||
|
||||
public function __sleep(): array
|
||||
{
|
||||
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function __wakeup()
|
||||
{
|
||||
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if (null === $this->prefixes) {
|
||||
$this->collection->addPrefix($this->route->getPath());
|
||||
}
|
||||
if (null !== $this->host) {
|
||||
$this->addHost($this->collection, $this->host);
|
||||
}
|
||||
|
||||
$this->parent->addCollection($this->collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a sub-collection.
|
||||
*/
|
||||
final public function collection(string $name = ''): self
|
||||
{
|
||||
return new self($this->collection, $this->name.$name, $this, $this->prefixes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the prefix to add to the path of all child routes.
|
||||
*
|
||||
* @param string|array $prefix the prefix, or the localized prefixes
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final public function prefix(string|array $prefix): static
|
||||
{
|
||||
if (\is_array($prefix)) {
|
||||
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))));
|
||||
} 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));
|
||||
}
|
||||
|
||||
$prefix[$locale] = $this->parentPrefixes[$locale].$localePrefix;
|
||||
}
|
||||
}
|
||||
$this->prefixes = $prefix;
|
||||
$this->route->setPath('/');
|
||||
} else {
|
||||
$this->prefixes = null;
|
||||
$this->route->setPath($prefix);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the host to use for all child routes.
|
||||
*
|
||||
* @param string|array $host the host, or the localized hosts
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final public function host(string|array $host): static
|
||||
{
|
||||
$this->host = $host;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method overrides the one from LocalizedRouteTrait.
|
||||
*/
|
||||
private function createRoute(string $path): Route
|
||||
{
|
||||
return (clone $this->route)->setPath($path);
|
||||
}
|
||||
}
|
90
vendor/symfony/routing/Loader/Configurator/ImportConfigurator.php
vendored
Normal file
90
vendor/symfony/routing/Loader/Configurator/ImportConfigurator.php
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
<?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\Configurator;
|
||||
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ImportConfigurator
|
||||
{
|
||||
use Traits\HostTrait;
|
||||
use Traits\PrefixTrait;
|
||||
use Traits\RouteTrait;
|
||||
|
||||
private RouteCollection $parent;
|
||||
|
||||
public function __construct(RouteCollection $parent, RouteCollection $route)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
$this->route = $route;
|
||||
}
|
||||
|
||||
public function __sleep(): array
|
||||
{
|
||||
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function __wakeup()
|
||||
{
|
||||
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
$this->parent->addCollection($this->route);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the prefix to add to the path of all child routes.
|
||||
*
|
||||
* @param string|array $prefix the prefix, or the localized prefixes
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final public function prefix(string|array $prefix, bool $trailingSlashOnRoot = true): static
|
||||
{
|
||||
$this->addPrefix($this->route, $prefix, $trailingSlashOnRoot);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the prefix to add to the name of all child routes.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final public function namePrefix(string $namePrefix): static
|
||||
{
|
||||
$this->route->addNamePrefix($namePrefix);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the host to use for all child routes.
|
||||
*
|
||||
* @param string|array $host the host, or the localized hosts
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final public function host(string|array $host): static
|
||||
{
|
||||
$this->addHost($this->route, $host);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
49
vendor/symfony/routing/Loader/Configurator/RouteConfigurator.php
vendored
Normal file
49
vendor/symfony/routing/Loader/Configurator/RouteConfigurator.php
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
<?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\Configurator;
|
||||
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class RouteConfigurator
|
||||
{
|
||||
use Traits\AddTrait;
|
||||
use Traits\HostTrait;
|
||||
use Traits\RouteTrait;
|
||||
|
||||
protected $parentConfigurator;
|
||||
|
||||
public function __construct(RouteCollection $collection, RouteCollection $route, string $name = '', ?CollectionConfigurator $parentConfigurator = null, ?array $prefixes = null)
|
||||
{
|
||||
$this->collection = $collection;
|
||||
$this->route = $route;
|
||||
$this->name = $name;
|
||||
$this->parentConfigurator = $parentConfigurator; // for GC control
|
||||
$this->prefixes = $prefixes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the host to use for all child routes.
|
||||
*
|
||||
* @param string|array $host the host, or the localized hosts
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final public function host(string|array $host): static
|
||||
{
|
||||
$this->addHost($this->route, $host);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
78
vendor/symfony/routing/Loader/Configurator/RoutingConfigurator.php
vendored
Normal file
78
vendor/symfony/routing/Loader/Configurator/RoutingConfigurator.php
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
<?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\Configurator;
|
||||
|
||||
use Symfony\Component\Routing\Loader\PhpFileLoader;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
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)
|
||||
{
|
||||
$this->collection = $collection;
|
||||
$this->loader = $loader;
|
||||
$this->path = $path;
|
||||
$this->file = $file;
|
||||
$this->env = $env;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|string[]|null $exclude Glob patterns to exclude from the import
|
||||
*/
|
||||
final public function import(string|array $resource, ?string $type = null, bool $ignoreErrors = false, string|array|null $exclude = null): ImportConfigurator
|
||||
{
|
||||
$this->loader->setCurrentDir(\dirname($this->path));
|
||||
|
||||
$imported = $this->loader->import($resource, $type, $ignoreErrors, $this->file, $exclude) ?: [];
|
||||
if (!\is_array($imported)) {
|
||||
return new ImportConfigurator($this->collection, $imported);
|
||||
}
|
||||
|
||||
$mergedCollection = new RouteCollection();
|
||||
foreach ($imported as $subCollection) {
|
||||
$mergedCollection->addCollection($subCollection);
|
||||
}
|
||||
|
||||
return new ImportConfigurator($this->collection, $mergedCollection);
|
||||
}
|
||||
|
||||
final public function collection(string $name = ''): CollectionConfigurator
|
||||
{
|
||||
return new CollectionConfigurator($this->collection, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current environment to be able to write conditional configuration.
|
||||
*/
|
||||
final public function env(): ?string
|
||||
{
|
||||
return $this->env;
|
||||
}
|
||||
|
||||
final public function withPath(string $path): static
|
||||
{
|
||||
$clone = clone $this;
|
||||
$clone->path = $clone->file = $path;
|
||||
|
||||
return $clone;
|
||||
}
|
||||
}
|
60
vendor/symfony/routing/Loader/Configurator/Traits/AddTrait.php
vendored
Normal file
60
vendor/symfony/routing/Loader/Configurator/Traits/AddTrait.php
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
<?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\Configurator\Traits;
|
||||
|
||||
use Symfony\Component\Routing\Loader\Configurator\AliasConfigurator;
|
||||
use Symfony\Component\Routing\Loader\Configurator\CollectionConfigurator;
|
||||
use Symfony\Component\Routing\Loader\Configurator\RouteConfigurator;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
trait AddTrait
|
||||
{
|
||||
use LocalizedRouteTrait;
|
||||
|
||||
/**
|
||||
* @var RouteCollection
|
||||
*/
|
||||
protected $collection;
|
||||
protected $name = '';
|
||||
protected $prefixes;
|
||||
|
||||
/**
|
||||
* Adds a route.
|
||||
*
|
||||
* @param string|array $path the path, or the localized paths of the route
|
||||
*/
|
||||
public function add(string $name, string|array $path): RouteConfigurator
|
||||
{
|
||||
$parentConfigurator = $this instanceof CollectionConfigurator ? $this : ($this instanceof RouteConfigurator ? $this->parentConfigurator : null);
|
||||
$route = $this->createLocalizedRoute($this->collection, $name, $path, $this->name, $this->prefixes);
|
||||
|
||||
return new RouteConfigurator($this->collection, $route, $this->name, $parentConfigurator, $this->prefixes);
|
||||
}
|
||||
|
||||
public function alias(string $name, string $alias): AliasConfigurator
|
||||
{
|
||||
return new AliasConfigurator($this->collection->addAlias($name, $alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a route.
|
||||
*
|
||||
* @param string|array $path the path, or the localized paths of the route
|
||||
*/
|
||||
public function __invoke(string $name, string|array $path): RouteConfigurator
|
||||
{
|
||||
return $this->add($name, $path);
|
||||
}
|
||||
}
|
49
vendor/symfony/routing/Loader/Configurator/Traits/HostTrait.php
vendored
Normal file
49
vendor/symfony/routing/Loader/Configurator/Traits/HostTrait.php
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
<?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\Configurator\Traits;
|
||||
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait HostTrait
|
||||
{
|
||||
final protected function addHost(RouteCollection $routes, string|array $hosts): void
|
||||
{
|
||||
if (!$hosts || !\is_array($hosts)) {
|
||||
$routes->setHost($hosts ?: '');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($routes->all() as $name => $route) {
|
||||
if (null === $locale = $route->getDefault('_locale')) {
|
||||
$routes->remove($name);
|
||||
foreach ($hosts as $locale => $host) {
|
||||
$localizedRoute = clone $route;
|
||||
$localizedRoute->setDefault('_locale', $locale);
|
||||
$localizedRoute->setRequirement('_locale', preg_quote($locale));
|
||||
$localizedRoute->setDefault('_canonical_route', $name);
|
||||
$localizedRoute->setHost($host);
|
||||
$routes->add($name.'.'.$locale, $localizedRoute);
|
||||
}
|
||||
} elseif (!isset($hosts[$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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
76
vendor/symfony/routing/Loader/Configurator/Traits/LocalizedRouteTrait.php
vendored
Normal file
76
vendor/symfony/routing/Loader/Configurator/Traits/LocalizedRouteTrait.php
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Routing\Loader\Configurator\Traits;
|
||||
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
* @author Jules Pietri <jules@heahprod.com>
|
||||
*/
|
||||
trait LocalizedRouteTrait
|
||||
{
|
||||
/**
|
||||
* Creates one or many routes.
|
||||
*
|
||||
* @param string|array $path the path, or the localized paths of the route
|
||||
*/
|
||||
final protected function createLocalizedRoute(RouteCollection $collection, string $name, string|array $path, string $namePrefix = '', ?array $prefixes = null): RouteCollection
|
||||
{
|
||||
$paths = [];
|
||||
|
||||
$routes = new RouteCollection();
|
||||
|
||||
if (\is_array($path)) {
|
||||
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))));
|
||||
} 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));
|
||||
}
|
||||
|
||||
$paths[$locale] = $prefixes[$locale].$localePath;
|
||||
}
|
||||
}
|
||||
} elseif (null !== $prefixes) {
|
||||
foreach ($prefixes as $locale => $prefix) {
|
||||
$paths[$locale] = $prefix.$path;
|
||||
}
|
||||
} else {
|
||||
$routes->add($namePrefix.$name, $route = $this->createRoute($path));
|
||||
$collection->add($namePrefix.$name, $route);
|
||||
|
||||
return $routes;
|
||||
}
|
||||
|
||||
foreach ($paths as $locale => $path) {
|
||||
$routes->add($name.'.'.$locale, $route = $this->createRoute($path));
|
||||
$collection->add($namePrefix.$name.'.'.$locale, $route);
|
||||
$route->setDefault('_locale', $locale);
|
||||
$route->setRequirement('_locale', preg_quote($locale));
|
||||
$route->setDefault('_canonical_route', $namePrefix.$name);
|
||||
}
|
||||
|
||||
return $routes;
|
||||
}
|
||||
|
||||
private function createRoute(string $path): Route
|
||||
{
|
||||
return new Route($path);
|
||||
}
|
||||
}
|
63
vendor/symfony/routing/Loader/Configurator/Traits/PrefixTrait.php
vendored
Normal file
63
vendor/symfony/routing/Loader/Configurator/Traits/PrefixTrait.php
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
<?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\Configurator\Traits;
|
||||
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
trait PrefixTrait
|
||||
{
|
||||
final protected function addPrefix(RouteCollection $routes, string|array $prefix, bool $trailingSlashOnRoot): void
|
||||
{
|
||||
if (\is_array($prefix)) {
|
||||
foreach ($prefix as $locale => $localePrefix) {
|
||||
$prefix[$locale] = trim(trim($localePrefix), '/');
|
||||
}
|
||||
foreach ($routes->all() as $name => $route) {
|
||||
if (null === $locale = $route->getDefault('_locale')) {
|
||||
$priority = $routes->getPriority($name) ?? 0;
|
||||
$routes->remove($name);
|
||||
foreach ($prefix as $locale => $localePrefix) {
|
||||
$localizedRoute = clone $route;
|
||||
$localizedRoute->setDefault('_locale', $locale);
|
||||
$localizedRoute->setRequirement('_locale', preg_quote($locale));
|
||||
$localizedRoute->setDefault('_canonical_route', $name);
|
||||
$localizedRoute->setPath($localePrefix.(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath()));
|
||||
$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));
|
||||
} else {
|
||||
$route->setPath($prefix[$locale].(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath()));
|
||||
$routes->add($name, $route, $routes->getPriority($name) ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$routes->addPrefix($prefix);
|
||||
if (!$trailingSlashOnRoot) {
|
||||
$rootPath = (new Route(trim(trim($prefix), '/').'/'))->getPath();
|
||||
foreach ($routes->all() as $route) {
|
||||
if ($route->getPath() === $rootPath) {
|
||||
$route->setPath(rtrim($rootPath, '/'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
175
vendor/symfony/routing/Loader/Configurator/Traits/RouteTrait.php
vendored
Normal file
175
vendor/symfony/routing/Loader/Configurator/Traits/RouteTrait.php
vendored
Normal file
@ -0,0 +1,175 @@
|
||||
<?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\Configurator\Traits;
|
||||
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
trait RouteTrait
|
||||
{
|
||||
/**
|
||||
* @var RouteCollection|Route
|
||||
*/
|
||||
protected $route;
|
||||
|
||||
/**
|
||||
* Adds defaults.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final public function defaults(array $defaults): static
|
||||
{
|
||||
$this->route->addDefaults($defaults);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds requirements.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final public function requirements(array $requirements): static
|
||||
{
|
||||
$this->route->addRequirements($requirements);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds options.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final public function options(array $options): static
|
||||
{
|
||||
$this->route->addOptions($options);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether paths should accept utf8 encoding.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final public function utf8(bool $utf8 = true): static
|
||||
{
|
||||
$this->route->addOptions(['utf8' => $utf8]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the condition.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final public function condition(string $condition): static
|
||||
{
|
||||
$this->route->setCondition($condition);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pattern for the host.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final public function host(string $pattern): static
|
||||
{
|
||||
$this->route->setHost($pattern);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the schemes (e.g. 'https') this route is restricted to.
|
||||
* So an empty array means that any scheme is allowed.
|
||||
*
|
||||
* @param string[] $schemes
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final public function schemes(array $schemes): static
|
||||
{
|
||||
$this->route->setSchemes($schemes);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the HTTP methods (e.g. 'POST') this route is restricted to.
|
||||
* So an empty array means that any method is allowed.
|
||||
*
|
||||
* @param string[] $methods
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final public function methods(array $methods): static
|
||||
{
|
||||
$this->route->setMethods($methods);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the "_controller" entry to defaults.
|
||||
*
|
||||
* @param callable|string|array $controller a callable or parseable pseudo-callable
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final public function controller(callable|string|array $controller): static
|
||||
{
|
||||
$this->route->addDefaults(['_controller' => $controller]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the "_locale" entry to defaults.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final public function locale(string $locale): static
|
||||
{
|
||||
$this->route->addDefaults(['_locale' => $locale]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the "_format" entry to defaults.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final public function format(string $format): static
|
||||
{
|
||||
$this->route->addDefaults(['_format' => $format]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the "_stateless" entry to defaults.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
final public function stateless(bool $stateless = true): static
|
||||
{
|
||||
$this->route->addDefaults(['_stateless' => $stateless]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
40
vendor/symfony/routing/Loader/ContainerLoader.php
vendored
Normal file
40
vendor/symfony/routing/Loader/ContainerLoader.php
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Routing\Loader;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* A route loader that executes a service from a PSR-11 container to load the routes.
|
||||
*
|
||||
* @author Ryan Weaver <ryan@knpuniversity.com>
|
||||
*/
|
||||
class ContainerLoader extends ObjectLoader
|
||||
{
|
||||
private ContainerInterface $container;
|
||||
|
||||
public function __construct(ContainerInterface $container, ?string $env = null)
|
||||
{
|
||||
$this->container = $container;
|
||||
parent::__construct($env);
|
||||
}
|
||||
|
||||
public function supports(mixed $resource, ?string $type = null): bool
|
||||
{
|
||||
return 'service' === $type && \is_string($resource);
|
||||
}
|
||||
|
||||
protected function getObject(string $id): object
|
||||
{
|
||||
return $this->container->get($id);
|
||||
}
|
||||
}
|
52
vendor/symfony/routing/Loader/DirectoryLoader.php
vendored
Normal file
52
vendor/symfony/routing/Loader/DirectoryLoader.php
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Routing\Loader;
|
||||
|
||||
use Symfony\Component\Config\Loader\FileLoader;
|
||||
use Symfony\Component\Config\Resource\DirectoryResource;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
class DirectoryLoader extends FileLoader
|
||||
{
|
||||
public function load(mixed $file, ?string $type = null): mixed
|
||||
{
|
||||
$path = $this->locator->locate($file);
|
||||
|
||||
$collection = new RouteCollection();
|
||||
$collection->addResource(new DirectoryResource($path));
|
||||
|
||||
foreach (scandir($path) as $dir) {
|
||||
if ('.' !== $dir[0]) {
|
||||
$this->setCurrentDir($path);
|
||||
$subPath = $path.'/'.$dir;
|
||||
$subType = null;
|
||||
|
||||
if (is_dir($subPath)) {
|
||||
$subPath .= '/';
|
||||
$subType = 'directory';
|
||||
}
|
||||
|
||||
$subCollection = $this->import($subPath, $subType, false, $path);
|
||||
$collection->addCollection($subCollection);
|
||||
}
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
public function supports(mixed $resource, ?string $type = null): bool
|
||||
{
|
||||
// only when type is forced to directory, not to conflict with AttributeLoader
|
||||
|
||||
return 'directory' === $type;
|
||||
}
|
||||
}
|
41
vendor/symfony/routing/Loader/GlobFileLoader.php
vendored
Normal file
41
vendor/symfony/routing/Loader/GlobFileLoader.php
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Routing\Loader;
|
||||
|
||||
use Symfony\Component\Config\Loader\FileLoader;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* GlobFileLoader loads files from a glob pattern.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class GlobFileLoader extends FileLoader
|
||||
{
|
||||
public function load(mixed $resource, ?string $type = null): mixed
|
||||
{
|
||||
$collection = new RouteCollection();
|
||||
|
||||
foreach ($this->glob($resource, false, $globResource) as $path => $info) {
|
||||
$collection->addCollection($this->import($path));
|
||||
}
|
||||
|
||||
$collection->addResource($globResource);
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
public function supports(mixed $resource, ?string $type = null): bool
|
||||
{
|
||||
return 'glob' === $type;
|
||||
}
|
||||
}
|
77
vendor/symfony/routing/Loader/ObjectLoader.php
vendored
Normal file
77
vendor/symfony/routing/Loader/ObjectLoader.php
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Routing\Loader;
|
||||
|
||||
use Symfony\Component\Config\Loader\Loader;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* A route loader that calls a method on an object to load the routes.
|
||||
*
|
||||
* @author Ryan Weaver <ryan@knpuniversity.com>
|
||||
*/
|
||||
abstract class ObjectLoader extends Loader
|
||||
{
|
||||
/**
|
||||
* Returns the object that the method will be called on to load routes.
|
||||
*
|
||||
* For example, if your application uses a service container,
|
||||
* the $id may be a service id.
|
||||
*/
|
||||
abstract protected function getObject(string $id): object;
|
||||
|
||||
/**
|
||||
* Calls the object method that will load the routes.
|
||||
*/
|
||||
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'));
|
||||
}
|
||||
|
||||
$parts = explode('::', $resource);
|
||||
$method = $parts[1] ?? '__invoke';
|
||||
|
||||
$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));
|
||||
}
|
||||
|
||||
$routeCollection = $loaderObject->$method($this, $this->env);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
// make the object file tracked so that if it changes, the cache rebuilds
|
||||
$this->addClassResource(new \ReflectionClass($loaderObject), $routeCollection);
|
||||
|
||||
return $routeCollection;
|
||||
}
|
||||
|
||||
private function addClassResource(\ReflectionClass $class, RouteCollection $collection): void
|
||||
{
|
||||
do {
|
||||
if (is_file($class->getFileName())) {
|
||||
$collection->addResource(new FileResource($class->getFileName()));
|
||||
}
|
||||
} while ($class = $class->getParentClass());
|
||||
}
|
||||
}
|
77
vendor/symfony/routing/Loader/PhpFileLoader.php
vendored
Normal file
77
vendor/symfony/routing/Loader/PhpFileLoader.php
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Routing\Loader;
|
||||
|
||||
use Symfony\Component\Config\Loader\FileLoader;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* PhpFileLoader loads routes from a PHP file.
|
||||
*
|
||||
* The file must return a RouteCollection instance.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Nicolas grekas <p@tchwork.com>
|
||||
* @author Jules Pietri <jules@heahprod.com>
|
||||
*/
|
||||
class PhpFileLoader extends FileLoader
|
||||
{
|
||||
/**
|
||||
* Loads a PHP file.
|
||||
*/
|
||||
public function load(mixed $file, ?string $type = null): RouteCollection
|
||||
{
|
||||
$path = $this->locator->locate($file);
|
||||
$this->setCurrentDir(\dirname($path));
|
||||
|
||||
// the closure forbids access to the private scope in the included file
|
||||
$loader = $this;
|
||||
$load = \Closure::bind(static function ($file) use ($loader) {
|
||||
return include $file;
|
||||
}, null, ProtectedPhpFileLoader::class);
|
||||
|
||||
$result = $load($path);
|
||||
|
||||
if (\is_object($result) && \is_callable($result)) {
|
||||
$collection = $this->callConfigurator($result, $path, $file);
|
||||
} else {
|
||||
$collection = $result;
|
||||
}
|
||||
|
||||
$collection->addResource(new FileResource($path));
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
public function supports(mixed $resource, ?string $type = null): bool
|
||||
{
|
||||
return \is_string($resource) && 'php' === pathinfo($resource, \PATHINFO_EXTENSION) && (!$type || 'php' === $type);
|
||||
}
|
||||
|
||||
protected function callConfigurator(callable $result, string $path, string $file): RouteCollection
|
||||
{
|
||||
$collection = new RouteCollection();
|
||||
|
||||
$result(new RoutingConfigurator($collection, $this, $path, $file, $this->env));
|
||||
|
||||
return $collection;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class ProtectedPhpFileLoader extends PhpFileLoader
|
||||
{
|
||||
}
|
91
vendor/symfony/routing/Loader/Psr4DirectoryLoader.php
vendored
Normal file
91
vendor/symfony/routing/Loader/Psr4DirectoryLoader.php
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Routing\Loader;
|
||||
|
||||
use Symfony\Component\Config\FileLocatorInterface;
|
||||
use Symfony\Component\Config\Loader\DirectoryAwareLoaderInterface;
|
||||
use Symfony\Component\Config\Loader\Loader;
|
||||
use Symfony\Component\Config\Resource\DirectoryResource;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* A loader that discovers controller classes in a directory that follows PSR-4.
|
||||
*
|
||||
* @author Alexander M. Turek <me@derrabus.de>
|
||||
*/
|
||||
final class Psr4DirectoryLoader extends Loader implements DirectoryAwareLoaderInterface
|
||||
{
|
||||
private ?string $currentDirectory = null;
|
||||
|
||||
public function __construct(
|
||||
private readonly FileLocatorInterface $locator,
|
||||
) {
|
||||
// PSR-4 directory loader has no env-aware logic, so we drop the $env constructor parameter.
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{path: string, namespace: string} $resource
|
||||
*/
|
||||
public function load(mixed $resource, ?string $type = null): ?RouteCollection
|
||||
{
|
||||
$path = $this->locator->locate($resource['path'], $this->currentDirectory);
|
||||
if (!is_dir($path)) {
|
||||
return new RouteCollection();
|
||||
}
|
||||
|
||||
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']);
|
||||
}
|
||||
|
||||
public function forDirectory(string $currentDirectory): static
|
||||
{
|
||||
$loader = clone $this;
|
||||
$loader->currentDirectory = $currentDirectory;
|
||||
|
||||
return $loader;
|
||||
}
|
||||
|
||||
private function loadFromDirectory(string $directory, string $psr4Prefix): RouteCollection
|
||||
{
|
||||
$collection = new RouteCollection();
|
||||
$collection->addResource(new DirectoryResource($directory, '/\.php$/'));
|
||||
$files = iterator_to_array(new \RecursiveIteratorIterator(
|
||||
new \RecursiveCallbackFilterIterator(
|
||||
new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS),
|
||||
fn (\SplFileInfo $current) => !str_starts_with($current->getBasename(), '.')
|
||||
),
|
||||
\RecursiveIteratorIterator::SELF_FIRST
|
||||
));
|
||||
usort($files, fn (\SplFileInfo $a, \SplFileInfo $b) => (string) $a > (string) $b ? 1 : -1);
|
||||
|
||||
/** @var \SplFileInfo $file */
|
||||
foreach ($files as $file) {
|
||||
if ($file->isDir()) {
|
||||
$collection->addCollection($this->loadFromDirectory($file->getPathname(), $psr4Prefix.'\\'.$file->getFilename()));
|
||||
|
||||
continue;
|
||||
}
|
||||
if ('php' !== $file->getExtension() || !class_exists($className = $psr4Prefix.'\\'.$file->getBasename('.php')) || (new \ReflectionClass($className))->isAbstract()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$collection->addCollection($this->import($className, 'attribute'));
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
}
|
470
vendor/symfony/routing/Loader/XmlFileLoader.php
vendored
Normal file
470
vendor/symfony/routing/Loader/XmlFileLoader.php
vendored
Normal file
@ -0,0 +1,470 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Routing\Loader;
|
||||
|
||||
use Symfony\Component\Config\Loader\FileLoader;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Config\Util\XmlUtils;
|
||||
use Symfony\Component\Routing\Loader\Configurator\Traits\HostTrait;
|
||||
use Symfony\Component\Routing\Loader\Configurator\Traits\LocalizedRouteTrait;
|
||||
use Symfony\Component\Routing\Loader\Configurator\Traits\PrefixTrait;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* XmlFileLoader loads XML routing files.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Tobias Schultze <http://tobion.de>
|
||||
*/
|
||||
class XmlFileLoader extends FileLoader
|
||||
{
|
||||
use HostTrait;
|
||||
use LocalizedRouteTrait;
|
||||
use PrefixTrait;
|
||||
|
||||
public const NAMESPACE_URI = 'http://symfony.com/schema/routing';
|
||||
public const SCHEME_PATH = '/schema/routing/routing-1.0.xsd';
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException when the file cannot be loaded or when the XML cannot be
|
||||
* parsed because it does not validate against the scheme
|
||||
*/
|
||||
public function load(mixed $file, ?string $type = null): RouteCollection
|
||||
{
|
||||
$path = $this->locator->locate($file);
|
||||
|
||||
$xml = $this->loadFile($path);
|
||||
|
||||
$collection = new RouteCollection();
|
||||
$collection->addResource(new FileResource($path));
|
||||
|
||||
// process routes and imports
|
||||
foreach ($xml->documentElement->childNodes as $node) {
|
||||
if (!$node instanceof \DOMElement) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->parseNode($collection, $node, $path, $file);
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a node from a loaded XML file.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws \InvalidArgumentException When the XML is invalid
|
||||
*/
|
||||
protected function parseNode(RouteCollection $collection, \DOMElement $node, string $path, string $file)
|
||||
{
|
||||
if (self::NAMESPACE_URI !== $node->namespaceURI) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch ($node->localName) {
|
||||
case 'route':
|
||||
$this->parseRoute($collection, $node, $path);
|
||||
break;
|
||||
case 'import':
|
||||
$this->parseImport($collection, $node, $path, $file);
|
||||
break;
|
||||
case 'when':
|
||||
if (!$this->env || $node->getAttribute('env') !== $this->env) {
|
||||
break;
|
||||
}
|
||||
foreach ($node->childNodes as $node) {
|
||||
if ($node instanceof \DOMElement) {
|
||||
$this->parseNode($collection, $node, $path, $file);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException(sprintf('Unknown tag "%s" used in file "%s". Expected "route" or "import".', $node->localName, $path));
|
||||
}
|
||||
}
|
||||
|
||||
public function supports(mixed $resource, ?string $type = null): bool
|
||||
{
|
||||
return \is_string($resource) && 'xml' === pathinfo($resource, \PATHINFO_EXTENSION) && (!$type || 'xml' === $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if ('' === $id = $node->getAttribute('id')) {
|
||||
throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" must have an "id" attribute.', $path));
|
||||
}
|
||||
|
||||
if ('' !== $alias = $node->getAttribute('alias')) {
|
||||
$alias = $collection->addAlias($id, $alias);
|
||||
|
||||
if ($deprecationInfo = $this->parseDeprecation($node, $path)) {
|
||||
$alias->setDeprecated($deprecationInfo['package'], $deprecationInfo['version'], $deprecationInfo['message']);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$schemes = preg_split('/[\s,\|]++/', $node->getAttribute('schemes'), -1, \PREG_SPLIT_NO_EMPTY);
|
||||
$methods = preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, \PREG_SPLIT_NO_EMPTY);
|
||||
|
||||
[$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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
$routes = $this->createLocalizedRoute($collection, $id, $paths ?: $node->getAttribute('path'));
|
||||
$routes->addDefaults($defaults);
|
||||
$routes->addRequirements($requirements);
|
||||
$routes->addOptions($options);
|
||||
$routes->setSchemes($schemes);
|
||||
$routes->setMethods($methods);
|
||||
$routes->setCondition($condition);
|
||||
|
||||
if (null !== $hosts) {
|
||||
$this->addHost($routes, $hosts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
/** @var \DOMElement $resourceElement */
|
||||
if (!($resource = $node->getAttribute('resource') ?: null) && $resourceElement = $node->getElementsByTagName('resource')[0] ?? null) {
|
||||
$resource = [];
|
||||
/** @var \DOMAttr $attribute */
|
||||
foreach ($resourceElement->attributes as $attribute) {
|
||||
$resource[$attribute->name] = $attribute->value;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$resource) {
|
||||
throw new \InvalidArgumentException(sprintf('The <import> element in file "%s" must have a "resource" attribute or element.', $path));
|
||||
}
|
||||
|
||||
$type = $node->getAttribute('type');
|
||||
$prefix = $node->getAttribute('prefix');
|
||||
$schemes = $node->hasAttribute('schemes') ? preg_split('/[\s,\|]++/', $node->getAttribute('schemes'), -1, \PREG_SPLIT_NO_EMPTY) : null;
|
||||
$methods = $node->hasAttribute('methods') ? preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, \PREG_SPLIT_NO_EMPTY) : null;
|
||||
$trailingSlashOnRoot = $node->hasAttribute('trailing-slash-on-root') ? XmlUtils::phpize($node->getAttribute('trailing-slash-on-root')) : true;
|
||||
$namePrefix = $node->getAttribute('name-prefix') ?: null;
|
||||
|
||||
[$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));
|
||||
}
|
||||
|
||||
$exclude = [];
|
||||
foreach ($node->childNodes as $child) {
|
||||
if ($child instanceof \DOMElement && $child->localName === $exclude && self::NAMESPACE_URI === $child->namespaceURI) {
|
||||
$exclude[] = $child->nodeValue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($node->hasAttribute('exclude')) {
|
||||
if ($exclude) {
|
||||
throw new \InvalidArgumentException('You cannot use both the attribute "exclude" and <exclude> tags at the same time.');
|
||||
}
|
||||
$exclude = [$node->getAttribute('exclude')];
|
||||
}
|
||||
|
||||
$this->setCurrentDir(\dirname($path));
|
||||
|
||||
/** @var RouteCollection[] $imported */
|
||||
$imported = $this->import($resource, '' !== $type ? $type : null, false, $file, $exclude) ?: [];
|
||||
|
||||
if (!\is_array($imported)) {
|
||||
$imported = [$imported];
|
||||
}
|
||||
|
||||
foreach ($imported as $subCollection) {
|
||||
$this->addPrefix($subCollection, $prefixes ?: $prefix, $trailingSlashOnRoot);
|
||||
|
||||
if (null !== $hosts) {
|
||||
$this->addHost($subCollection, $hosts);
|
||||
}
|
||||
|
||||
if (null !== $condition) {
|
||||
$subCollection->setCondition($condition);
|
||||
}
|
||||
if (null !== $schemes) {
|
||||
$subCollection->setSchemes($schemes);
|
||||
}
|
||||
if (null !== $methods) {
|
||||
$subCollection->setMethods($methods);
|
||||
}
|
||||
if (null !== $namePrefix) {
|
||||
$subCollection->addNamePrefix($namePrefix);
|
||||
}
|
||||
$subCollection->addDefaults($defaults);
|
||||
$subCollection->addRequirements($requirements);
|
||||
$subCollection->addOptions($options);
|
||||
|
||||
$collection->addCollection($subCollection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException When loading of XML file fails because of syntax errors
|
||||
* or when the XML structure is not as expected by the scheme -
|
||||
* see validate()
|
||||
*/
|
||||
protected function loadFile(string $file): \DOMDocument
|
||||
{
|
||||
return XmlUtils::loadFile($file, __DIR__.static::SCHEME_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the config elements (default, requirement, option).
|
||||
*
|
||||
* @throws \InvalidArgumentException When the XML is invalid
|
||||
*/
|
||||
private function parseConfigs(\DOMElement $node, string $path): array
|
||||
{
|
||||
$defaults = [];
|
||||
$requirements = [];
|
||||
$options = [];
|
||||
$condition = null;
|
||||
$prefixes = [];
|
||||
$paths = [];
|
||||
$hosts = [];
|
||||
|
||||
/** @var \DOMElement $n */
|
||||
foreach ($node->getElementsByTagNameNS(self::NAMESPACE_URI, '*') as $n) {
|
||||
if ($node !== $n->parentNode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch ($n->localName) {
|
||||
case 'path':
|
||||
$paths[$n->getAttribute('locale')] = trim($n->textContent);
|
||||
break;
|
||||
case 'host':
|
||||
$hosts[$n->getAttribute('locale')] = trim($n->textContent);
|
||||
break;
|
||||
case 'prefix':
|
||||
$prefixes[$n->getAttribute('locale')] = trim($n->textContent);
|
||||
break;
|
||||
case 'default':
|
||||
if ($this->isElementValueNull($n)) {
|
||||
$defaults[$n->getAttribute('key')] = null;
|
||||
} else {
|
||||
$defaults[$n->getAttribute('key')] = $this->parseDefaultsConfig($n, $path);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'requirement':
|
||||
$requirements[$n->getAttribute('key')] = trim($n->textContent);
|
||||
break;
|
||||
case 'option':
|
||||
$options[$n->getAttribute('key')] = XmlUtils::phpize(trim($n->textContent));
|
||||
break;
|
||||
case 'condition':
|
||||
$condition = trim($n->textContent);
|
||||
break;
|
||||
case 'resource':
|
||||
break;
|
||||
default:
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
if ($node->hasAttribute('locale')) {
|
||||
$defaults['_locale'] = $node->getAttribute('locale');
|
||||
}
|
||||
if ($node->hasAttribute('format')) {
|
||||
$defaults['_format'] = $node->getAttribute('format');
|
||||
}
|
||||
if ($node->hasAttribute('utf8')) {
|
||||
$options['utf8'] = XmlUtils::phpize($node->getAttribute('utf8'));
|
||||
}
|
||||
if ($stateless = $node->getAttribute('stateless')) {
|
||||
if (isset($defaults['_stateless'])) {
|
||||
$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);
|
||||
}
|
||||
|
||||
$defaults['_stateless'] = XmlUtils::phpize($stateless);
|
||||
}
|
||||
|
||||
if (!$hosts) {
|
||||
$hosts = $node->hasAttribute('host') ? $node->getAttribute('host') : null;
|
||||
}
|
||||
|
||||
return [$defaults, $requirements, $options, $condition, $paths, $prefixes, $hosts];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the "default" elements.
|
||||
*/
|
||||
private function parseDefaultsConfig(\DOMElement $element, string $path): array|bool|float|int|string|null
|
||||
{
|
||||
if ($this->isElementValueNull($element)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check for existing element nodes in the default element. There can
|
||||
// only be a single element inside a default element. So this element
|
||||
// (if one was found) can safely be returned.
|
||||
foreach ($element->childNodes as $child) {
|
||||
if (!$child instanceof \DOMElement) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (self::NAMESPACE_URI !== $child->namespaceURI) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $this->parseDefaultNode($child, $path);
|
||||
}
|
||||
|
||||
// If the default element doesn't contain a nested "bool", "int", "float",
|
||||
// "string", "list", or "map" element, the element contents will be treated
|
||||
// as the string value of the associated default option.
|
||||
return trim($element->textContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively parses the value of a "default" element.
|
||||
*
|
||||
* @throws \InvalidArgumentException when the XML is invalid
|
||||
*/
|
||||
private function parseDefaultNode(\DOMElement $node, string $path): array|bool|float|int|string|null
|
||||
{
|
||||
if ($this->isElementValueNull($node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch ($node->localName) {
|
||||
case 'bool':
|
||||
return 'true' === trim($node->nodeValue) || '1' === trim($node->nodeValue);
|
||||
case 'int':
|
||||
return (int) trim($node->nodeValue);
|
||||
case 'float':
|
||||
return (float) trim($node->nodeValue);
|
||||
case 'string':
|
||||
return trim($node->nodeValue);
|
||||
case 'list':
|
||||
$list = [];
|
||||
|
||||
foreach ($node->childNodes as $element) {
|
||||
if (!$element instanceof \DOMElement) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (self::NAMESPACE_URI !== $element->namespaceURI) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$list[] = $this->parseDefaultNode($element, $path);
|
||||
}
|
||||
|
||||
return $list;
|
||||
case 'map':
|
||||
$map = [];
|
||||
|
||||
foreach ($node->childNodes as $element) {
|
||||
if (!$element instanceof \DOMElement) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (self::NAMESPACE_URI !== $element->namespaceURI) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$map[$element->getAttribute('key')] = $this->parseDefaultNode($element, $path);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
private function isElementValueNull(\DOMElement $element): bool
|
||||
{
|
||||
$namespaceUri = 'http://www.w3.org/2001/XMLSchema-instance';
|
||||
|
||||
if (!$element->hasAttributeNS($namespaceUri, 'nil')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return 'true' === $element->getAttributeNS($namespaceUri, 'nil') || '1' === $element->getAttributeNS($namespaceUri, 'nil');
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the deprecation elements.
|
||||
*
|
||||
* @throws \InvalidArgumentException When the XML is invalid
|
||||
*/
|
||||
private function parseDeprecation(\DOMElement $node, string $path): array
|
||||
{
|
||||
$deprecatedNode = null;
|
||||
foreach ($node->childNodes as $child) {
|
||||
if (!$child instanceof \DOMElement || self::NAMESPACE_URI !== $child->namespaceURI) {
|
||||
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));
|
||||
}
|
||||
|
||||
$deprecatedNode = $child;
|
||||
}
|
||||
|
||||
if (null === $deprecatedNode) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!$deprecatedNode->hasAttribute('package')) {
|
||||
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));
|
||||
}
|
||||
|
||||
return [
|
||||
'package' => $deprecatedNode->getAttribute('package'),
|
||||
'version' => $deprecatedNode->getAttribute('version'),
|
||||
'message' => trim($deprecatedNode->nodeValue),
|
||||
];
|
||||
}
|
||||
}
|
302
vendor/symfony/routing/Loader/YamlFileLoader.php
vendored
Normal file
302
vendor/symfony/routing/Loader/YamlFileLoader.php
vendored
Normal file
@ -0,0 +1,302 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Routing\Loader;
|
||||
|
||||
use Symfony\Component\Config\Loader\FileLoader;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Routing\Loader\Configurator\Traits\HostTrait;
|
||||
use Symfony\Component\Routing\Loader\Configurator\Traits\LocalizedRouteTrait;
|
||||
use Symfony\Component\Routing\Loader\Configurator\Traits\PrefixTrait;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
use Symfony\Component\Yaml\Exception\ParseException;
|
||||
use Symfony\Component\Yaml\Parser as YamlParser;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* YamlFileLoader loads Yaml routing files.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Tobias Schultze <http://tobion.de>
|
||||
*/
|
||||
class YamlFileLoader extends FileLoader
|
||||
{
|
||||
use HostTrait;
|
||||
use LocalizedRouteTrait;
|
||||
use PrefixTrait;
|
||||
|
||||
private const AVAILABLE_KEYS = [
|
||||
'resource', 'type', 'prefix', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition', 'controller', 'name_prefix', 'trailing_slash_on_root', 'locale', 'format', 'utf8', 'exclude', 'stateless',
|
||||
];
|
||||
private YamlParser $yamlParser;
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException When a route can't be parsed because YAML is invalid
|
||||
*/
|
||||
public function load(mixed $file, ?string $type = null): RouteCollection
|
||||
{
|
||||
$path = $this->locator->locate($file);
|
||||
|
||||
if (!stream_is_local($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));
|
||||
}
|
||||
|
||||
$this->yamlParser ??= new YamlParser();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
$collection = new RouteCollection();
|
||||
$collection->addResource(new FileResource($path));
|
||||
|
||||
// empty file
|
||||
if (null === $parsedConfig) {
|
||||
return $collection;
|
||||
}
|
||||
|
||||
// not an array
|
||||
if (!\is_array($parsedConfig)) {
|
||||
throw new \InvalidArgumentException(sprintf('The file "%s" must contain a YAML array.', $path));
|
||||
}
|
||||
|
||||
foreach ($parsedConfig as $name => $config) {
|
||||
if (str_starts_with($name, 'when@')) {
|
||||
if (!$this->env || 'when@'.$this->env !== $name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($config as $name => $config) {
|
||||
$this->validate($config, $name.'" when "@'.$this->env, $path);
|
||||
|
||||
if (isset($config['resource'])) {
|
||||
$this->parseImport($collection, $config, $path, $file);
|
||||
} else {
|
||||
$this->parseRoute($collection, $name, $config, $path);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->validate($config, $name, $path);
|
||||
|
||||
if (isset($config['resource'])) {
|
||||
$this->parseImport($collection, $config, $path, $file);
|
||||
} else {
|
||||
$this->parseRoute($collection, $name, $config, $path);
|
||||
}
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
public function supports(mixed $resource, ?string $type = null): bool
|
||||
{
|
||||
return \is_string($resource) && \in_array(pathinfo($resource, \PATHINFO_EXTENSION), ['yml', 'yaml'], true) && (!$type || 'yaml' === $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a route and adds it to the RouteCollection.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function parseRoute(RouteCollection $collection, string $name, array $config, string $path)
|
||||
{
|
||||
if (isset($config['alias'])) {
|
||||
$alias = $collection->addAlias($name, $config['alias']);
|
||||
$deprecation = $config['deprecated'] ?? null;
|
||||
if (null !== $deprecation) {
|
||||
$alias->setDeprecated(
|
||||
$deprecation['package'],
|
||||
$deprecation['version'],
|
||||
$deprecation['message'] ?? ''
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$defaults = $config['defaults'] ?? [];
|
||||
$requirements = $config['requirements'] ?? [];
|
||||
$options = $config['options'] ?? [];
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($config['controller'])) {
|
||||
$defaults['_controller'] = $config['controller'];
|
||||
}
|
||||
if (isset($config['locale'])) {
|
||||
$defaults['_locale'] = $config['locale'];
|
||||
}
|
||||
if (isset($config['format'])) {
|
||||
$defaults['_format'] = $config['format'];
|
||||
}
|
||||
if (isset($config['utf8'])) {
|
||||
$options['utf8'] = $config['utf8'];
|
||||
}
|
||||
if (isset($config['stateless'])) {
|
||||
$defaults['_stateless'] = $config['stateless'];
|
||||
}
|
||||
|
||||
$routes = $this->createLocalizedRoute($collection, $name, $config['path']);
|
||||
$routes->addDefaults($defaults);
|
||||
$routes->addRequirements($requirements);
|
||||
$routes->addOptions($options);
|
||||
$routes->setSchemes($config['schemes'] ?? []);
|
||||
$routes->setMethods($config['methods'] ?? []);
|
||||
$routes->setCondition($config['condition'] ?? null);
|
||||
|
||||
if (isset($config['host'])) {
|
||||
$this->addHost($routes, $config['host']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
$type = $config['type'] ?? null;
|
||||
$prefix = $config['prefix'] ?? '';
|
||||
$defaults = $config['defaults'] ?? [];
|
||||
$requirements = $config['requirements'] ?? [];
|
||||
$options = $config['options'] ?? [];
|
||||
$host = $config['host'] ?? null;
|
||||
$condition = $config['condition'] ?? null;
|
||||
$schemes = $config['schemes'] ?? null;
|
||||
$methods = $config['methods'] ?? null;
|
||||
$trailingSlashOnRoot = $config['trailing_slash_on_root'] ?? true;
|
||||
$namePrefix = $config['name_prefix'] ?? null;
|
||||
$exclude = $config['exclude'] ?? null;
|
||||
|
||||
if (isset($config['controller'])) {
|
||||
$defaults['_controller'] = $config['controller'];
|
||||
}
|
||||
if (isset($config['locale'])) {
|
||||
$defaults['_locale'] = $config['locale'];
|
||||
}
|
||||
if (isset($config['format'])) {
|
||||
$defaults['_format'] = $config['format'];
|
||||
}
|
||||
if (isset($config['utf8'])) {
|
||||
$options['utf8'] = $config['utf8'];
|
||||
}
|
||||
if (isset($config['stateless'])) {
|
||||
$defaults['_stateless'] = $config['stateless'];
|
||||
}
|
||||
|
||||
$this->setCurrentDir(\dirname($path));
|
||||
|
||||
/** @var RouteCollection[] $imported */
|
||||
$imported = $this->import($config['resource'], $type, false, $file, $exclude) ?: [];
|
||||
|
||||
if (!\is_array($imported)) {
|
||||
$imported = [$imported];
|
||||
}
|
||||
|
||||
foreach ($imported as $subCollection) {
|
||||
$this->addPrefix($subCollection, $prefix, $trailingSlashOnRoot);
|
||||
|
||||
if (null !== $host) {
|
||||
$this->addHost($subCollection, $host);
|
||||
}
|
||||
if (null !== $condition) {
|
||||
$subCollection->setCondition($condition);
|
||||
}
|
||||
if (null !== $schemes) {
|
||||
$subCollection->setSchemes($schemes);
|
||||
}
|
||||
if (null !== $methods) {
|
||||
$subCollection->setMethods($methods);
|
||||
}
|
||||
if (null !== $namePrefix) {
|
||||
$subCollection->addNamePrefix($namePrefix);
|
||||
}
|
||||
$subCollection->addDefaults($defaults);
|
||||
$subCollection->addRequirements($requirements);
|
||||
$subCollection->addOptions($options);
|
||||
|
||||
$collection->addCollection($subCollection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
if (!\is_array($config)) {
|
||||
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);
|
||||
|
||||
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)));
|
||||
}
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException If one of the provided config keys is not supported,
|
||||
* something is missing or the combination is nonsense
|
||||
*/
|
||||
private function validateAlias(array $config, string $name, string $path): void
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
201
vendor/symfony/routing/Loader/schema/routing/routing-1.0.xsd
vendored
Normal file
201
vendor/symfony/routing/Loader/schema/routing/routing-1.0.xsd
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<xsd:schema xmlns="http://symfony.com/schema/routing"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://symfony.com/schema/routing"
|
||||
elementFormDefault="qualified">
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Symfony XML Routing Schema, version 1.0
|
||||
Authors: Fabien Potencier, Tobias Schultze
|
||||
|
||||
This scheme defines the elements and attributes that can be used to define
|
||||
routes. A route maps an HTTP request to a set of configuration variables.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:element name="routes" type="routes" />
|
||||
|
||||
<xsd:complexType name="routes">
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element name="import" type="import" />
|
||||
<xsd:element name="route" type="route" />
|
||||
<xsd:element name="when" type="when" />
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="when">
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element name="import" type="import" />
|
||||
<xsd:element name="route" type="route" />
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="env" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="localized-path">
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="locale" type="xsd:string" use="required" />
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:group name="configs">
|
||||
<xsd:choice>
|
||||
<xsd:element name="default" nillable="true" type="default" />
|
||||
<xsd:element name="requirement" type="element" />
|
||||
<xsd:element name="option" type="element" />
|
||||
<xsd:element name="condition" type="xsd:string" />
|
||||
</xsd:choice>
|
||||
</xsd:group>
|
||||
|
||||
<xsd:complexType name="route">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="configs" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="path" type="localized-path" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="host" type="localized-path" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="deprecated" type="deprecated" minOccurs="0" maxOccurs="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="id" type="xsd:string" use="required" />
|
||||
<xsd:attribute name="path" type="xsd:string" />
|
||||
<xsd:attribute name="host" type="xsd:string" />
|
||||
<xsd:attribute name="schemes" type="xsd:string" />
|
||||
<xsd:attribute name="methods" type="xsd:string" />
|
||||
<xsd:attribute name="controller" type="xsd:string" />
|
||||
<xsd:attribute name="locale" type="xsd:string" />
|
||||
<xsd:attribute name="format" type="xsd:string" />
|
||||
<xsd:attribute name="utf8" type="xsd:boolean" />
|
||||
<xsd:attribute name="stateless" type="xsd:boolean" />
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="import">
|
||||
<xsd:sequence maxOccurs="unbounded" minOccurs="0">
|
||||
<xsd:group ref="configs" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="prefix" type="localized-path" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="exclude" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="host" type="localized-path" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="resource" type="resource" minOccurs="0" maxOccurs="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="resource" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="exclude" type="xsd:string" />
|
||||
<xsd:attribute name="prefix" type="xsd:string" />
|
||||
<xsd:attribute name="name-prefix" type="xsd:string" />
|
||||
<xsd:attribute name="host" type="xsd:string" />
|
||||
<xsd:attribute name="schemes" type="xsd:string" />
|
||||
<xsd:attribute name="methods" type="xsd:string" />
|
||||
<xsd:attribute name="controller" type="xsd:string" />
|
||||
<xsd:attribute name="locale" type="xsd:string" />
|
||||
<xsd:attribute name="format" type="xsd:string" />
|
||||
<xsd:attribute name="trailing-slash-on-root" type="xsd:boolean" />
|
||||
<xsd:attribute name="utf8" type="xsd:boolean" />
|
||||
<xsd:attribute name="stateless" type="xsd:boolean" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="resource">
|
||||
<xsd:attribute name="path" type="xsd:string" />
|
||||
<xsd:attribute name="namespace" type="xsd:string" />
|
||||
<xsd:anyAttribute />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="default" mixed="true">
|
||||
<xsd:choice minOccurs="0" maxOccurs="1">
|
||||
<xsd:element name="bool" type="xsd:boolean" />
|
||||
<xsd:element name="int" type="xsd:integer" />
|
||||
<xsd:element name="float" type="xsd:float" />
|
||||
<xsd:element name="string" type="xsd:string" />
|
||||
<xsd:element name="list" type="list" />
|
||||
<xsd:element name="map" type="map" />
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="key" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="element">
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="key" type="xsd:string" use="required" />
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="list">
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element name="bool" nillable="true" type="xsd:boolean" />
|
||||
<xsd:element name="int" nillable="true" type="xsd:integer" />
|
||||
<xsd:element name="float" nillable="true" type="xsd:float" />
|
||||
<xsd:element name="string" nillable="true" type="xsd:string" />
|
||||
<xsd:element name="list" nillable="true" type="list" />
|
||||
<xsd:element name="map" nillable="true" type="map" />
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="map">
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element name="bool" nillable="true" type="map-bool-entry" />
|
||||
<xsd:element name="int" nillable="true" type="map-int-entry" />
|
||||
<xsd:element name="float" nillable="true" type="map-float-entry" />
|
||||
<xsd:element name="string" nillable="true" type="map-string-entry" />
|
||||
<xsd:element name="list" nillable="true" type="map-list-entry" />
|
||||
<xsd:element name="map" nillable="true" type="map-map-entry" />
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="map-bool-entry">
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:boolean">
|
||||
<xsd:attribute name="key" type="xsd:string" use="required" />
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="map-int-entry">
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:integer">
|
||||
<xsd:attribute name="key" type="xsd:string" use="required" />
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="map-float-entry">
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:float">
|
||||
<xsd:attribute name="key" type="xsd:string" use="required" />
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="map-string-entry">
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="key" type="xsd:string" use="required" />
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="map-list-entry">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="list">
|
||||
<xsd:attribute name="key" type="xsd:string" use="required" />
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="map-map-entry">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="map">
|
||||
<xsd:attribute name="key" type="xsd:string" use="required" />
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="deprecated">
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="package" type="xsd:string" use="required" />
|
||||
<xsd:attribute name="version" type="xsd:string" use="required" />
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
</xsd:schema>
|
Reference in New Issue
Block a user