package and depencies

This commit is contained in:
RafficMohammed
2023-01-08 02:57:24 +05:30
parent d5332eb421
commit 1d54b8bc7f
4309 changed files with 193331 additions and 172289 deletions

View File

@@ -0,0 +1,84 @@
<?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\HttpKernel\Attribute;
/**
* Describes the default HTTP cache headers on controllers.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_FUNCTION)]
final class Cache
{
public function __construct(
/**
* The expiration date as a valid date for the strtotime() function.
*/
public ?string $expires = null,
/**
* The number of seconds that the response is considered fresh by a private
* cache like a web browser.
*/
public int|string|null $maxage = null,
/**
* The number of seconds that the response is considered fresh by a public
* cache like a reverse proxy cache.
*/
public int|string|null $smaxage = null,
/**
* Whether the response is public or not.
*/
public ?bool $public = null,
/**
* Whether or not the response must be revalidated.
*/
public bool $mustRevalidate = false,
/**
* Additional "Vary:"-headers.
*/
public array $vary = [],
/**
* An expression to compute the Last-Modified HTTP header.
*/
public ?string $lastModified = null,
/**
* An expression to compute the ETag HTTP header.
*/
public ?string $etag = null,
/**
* max-stale Cache-Control header
* It can be expressed in seconds or with a relative time format (1 day, 2 weeks, ...).
*/
public int|string|null $maxStale = null,
/**
* stale-while-revalidate Cache-Control header
* It can be expressed in seconds or with a relative time format (1 day, 2 weeks, ...).
*/
public int|string|null $staleWhileRevalidate = null,
/**
* stale-if-error Cache-Control header
* It can be expressed in seconds or with a relative time format (1 day, 2 weeks, ...).
*/
public int|string|null $staleIfError = null,
) {
}
}

View File

@@ -11,13 +11,14 @@
namespace Symfony\Component\HttpKernel\Attribute;
trigger_deprecation('symfony/http-kernel', '5.3', 'The "%s" interface is deprecated.', ArgumentInterface::class);
/**
* Marker interface for controller argument attributes.
*
* @deprecated since Symfony 5.3
* Controller parameter tag to configure DateTime arguments.
*/
interface ArgumentInterface
#[\Attribute(\Attribute::TARGET_PARAMETER)]
class MapDateTime
{
public function __construct(
public readonly ?string $format = null
) {
}
}

View File

@@ -0,0 +1,61 @@
<?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\HttpKernel\Bundle;
use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\ConfigurableExtensionInterface;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
/**
* A Bundle that provides configuration hooks.
*
* @author Yonel Ceruto <yonelceruto@gmail.com>
*/
abstract class AbstractBundle extends Bundle implements ConfigurableExtensionInterface
{
protected string $extensionAlias = '';
public function configure(DefinitionConfigurator $definition): void
{
}
public function prependExtension(ContainerConfigurator $container, ContainerBuilder $builder): void
{
}
public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
{
}
public function getContainerExtension(): ?ExtensionInterface
{
if ('' === $this->extensionAlias) {
$this->extensionAlias = Container::underscore(preg_replace('/Bundle$/', '', $this->getName()));
}
return $this->extension ??= new BundleExtension($this, $this->extensionAlias);
}
public function getPath(): string
{
if (null === $this->path) {
$reflected = new \ReflectionObject($this);
// assume the modern directory structure by default
$this->path = \dirname($reflected->getFileName(), 2);
}
return $this->path;
}
}

View File

@@ -29,25 +29,17 @@ abstract class Bundle implements BundleInterface
protected $name;
protected $extension;
protected $path;
private $namespace;
private string $namespace;
/**
* {@inheritdoc}
*/
public function boot()
{
}
/**
* {@inheritdoc}
*/
public function shutdown()
{
}
/**
* {@inheritdoc}
*
* This method can be overridden to register compilation passes,
* other extensions, ...
*/
@@ -58,11 +50,9 @@ abstract class Bundle implements BundleInterface
/**
* Returns the bundle's container extension.
*
* @return ExtensionInterface|null
*
* @throws \LogicException
*/
public function getContainerExtension()
public function getContainerExtension(): ?ExtensionInterface
{
if (null === $this->extension) {
$extension = $this->createContainerExtension();
@@ -89,22 +79,16 @@ abstract class Bundle implements BundleInterface
return $this->extension ?: null;
}
/**
* {@inheritdoc}
*/
public function getNamespace()
public function getNamespace(): string
{
if (null === $this->namespace) {
if (!isset($this->namespace)) {
$this->parseClassName();
}
return $this->namespace;
}
/**
* {@inheritdoc}
*/
public function getPath()
public function getPath(): string
{
if (null === $this->path) {
$reflected = new \ReflectionObject($this);
@@ -132,10 +116,8 @@ abstract class Bundle implements BundleInterface
/**
* Returns the bundle's container extension class.
*
* @return string
*/
protected function getContainerExtensionClass()
protected function getContainerExtensionClass(): string
{
$basename = preg_replace('/Bundle$/', '', $this->getName());
@@ -144,10 +126,8 @@ abstract class Bundle implements BundleInterface
/**
* Creates the bundle's container extension.
*
* @return ExtensionInterface|null
*/
protected function createContainerExtension()
protected function createContainerExtension(): ?ExtensionInterface
{
return class_exists($class = $this->getContainerExtensionClass()) ? new $class() : null;
}
@@ -156,8 +136,6 @@ abstract class Bundle implements BundleInterface
{
$pos = strrpos(static::class, '\\');
$this->namespace = false === $pos ? '' : substr(static::class, 0, $pos);
if (null === $this->name) {
$this->name = false === $pos ? static::class : substr(static::class, $pos + 1);
}
$this->name ??= false === $pos ? static::class : substr(static::class, $pos + 1);
}
}

View File

@@ -0,0 +1,67 @@
<?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\HttpKernel\Bundle;
use Symfony\Component\Config\Definition\Configuration;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\ConfigurableExtensionInterface;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Extension\ExtensionTrait;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
/**
* @author Yonel Ceruto <yonelceruto@gmail.com>
*
* @internal
*/
class BundleExtension extends Extension implements PrependExtensionInterface
{
use ExtensionTrait;
public function __construct(
private ConfigurableExtensionInterface $subject,
private string $alias,
) {
}
public function getConfiguration(array $config, ContainerBuilder $container): ?ConfigurationInterface
{
return new Configuration($this->subject, $container, $this->getAlias());
}
public function getAlias(): string
{
return $this->alias;
}
public function prepend(ContainerBuilder $container): void
{
$callback = function (ContainerConfigurator $configurator) use ($container) {
$this->subject->prependExtension($configurator, $container);
};
$this->executeConfiguratorCallback($container, $callback, $this->subject);
}
public function load(array $configs, ContainerBuilder $container): void
{
$config = $this->processConfiguration($this->getConfiguration([], $container), $configs);
$callback = function (ContainerConfigurator $configurator) use ($config, $container) {
$this->subject->loadExtension($config, $configurator, $container);
};
$this->executeConfiguratorCallback($container, $callback, $this->subject);
}
}

View File

@@ -41,31 +41,23 @@ interface BundleInterface extends ContainerAwareInterface
/**
* Returns the container extension that should be implicitly loaded.
*
* @return ExtensionInterface|null
*/
public function getContainerExtension();
public function getContainerExtension(): ?ExtensionInterface;
/**
* Returns the bundle name (the class short name).
*
* @return string
*/
public function getName();
public function getName(): string;
/**
* Gets the Bundle namespace.
*
* @return string
*/
public function getNamespace();
public function getNamespace(): string;
/**
* Gets the Bundle directory path.
*
* The path should always be returned as a Unix path (with /).
*
* @return string
*/
public function getPath();
public function getPath(): string;
}

View File

@@ -1,6 +1,37 @@
CHANGELOG
=========
6.2
---
* Add constructor argument `bool $handleAllThrowable` to `HttpKernel`
* Add `ControllerEvent::getAttributes()` to handle attributes on controllers
* Add `#[Cache]` to describe the default HTTP cache headers on controllers
* Add `absolute_uri` option to surrogate fragment renderers
* Add `ValueResolverInterface` and deprecate `ArgumentValueResolverInterface`
* Add argument `$reflector` to `ArgumentResolverInterface` and `ArgumentMetadataFactoryInterface`
* Deprecate calling `ConfigDataCollector::setKernel()`, `RouterListener::setCurrentRequest()` without arguments
6.1
---
* Add `BackedEnumValueResolver` to resolve backed enum cases from request attributes in controller arguments
* Add `DateTimeValueResolver` to resolve request attributes into DateTime objects in controller arguments
* Deprecate StreamedResponseListener, it's not needed anymore
* Add `Profiler::isEnabled()` so collaborating collector services may elect to omit themselves
* Add the `UidValueResolver` argument value resolver
* Add `AbstractBundle` class for DI configuration/definition on a single file
* Update the path of a bundle placed in the `src/` directory to the parent directory when `AbstractBundle` is used
6.0
---
* Remove `ArgumentInterface`
* Remove `ArgumentMetadata::getAttribute()`, use `getAttributes()` instead
* Remove support for returning a `ContainerBuilder` from `KernelInterface::registerContainerConfiguration()`
* Remove `KernelEvent::isMasterRequest()`, use `isMainRequest()` instead
* Remove support for `service:action` syntax to reference controllers, use `serviceOrFqcn::method` instead
5.4
---

View File

@@ -20,7 +20,7 @@ namespace Symfony\Component\HttpKernel\CacheClearer;
*/
class ChainCacheClearer implements CacheClearerInterface
{
private $clearers;
private iterable $clearers;
/**
* @param iterable<mixed, CacheClearerInterface> $clearers
@@ -30,9 +30,6 @@ class ChainCacheClearer implements CacheClearerInterface
$this->clearers = $clearers;
}
/**
* {@inheritdoc}
*/
public function clear(string $cacheDir)
{
foreach ($this->clearers as $clearer) {

View File

@@ -18,7 +18,7 @@ use Psr\Cache\CacheItemPoolInterface;
*/
class Psr6CacheClearer implements CacheClearerInterface
{
private $pools = [];
private array $pools = [];
/**
* @param array<string, CacheItemPoolInterface> $pools
@@ -28,20 +28,15 @@ class Psr6CacheClearer implements CacheClearerInterface
$this->pools = $pools;
}
/**
* @return bool
*/
public function hasPool(string $name)
public function hasPool(string $name): bool
{
return isset($this->pools[$name]);
}
/**
* @return CacheItemPoolInterface
*
* @throws \InvalidArgumentException If the cache pool with the given name does not exist
*/
public function getPool(string $name)
public function getPool(string $name): CacheItemPoolInterface
{
if (!$this->hasPool($name)) {
throw new \InvalidArgumentException(sprintf('Cache pool not found: "%s".', $name));
@@ -51,11 +46,9 @@ class Psr6CacheClearer implements CacheClearerInterface
}
/**
* @return bool
*
* @throws \InvalidArgumentException If the cache pool with the given name does not exist
*/
public function clearPool(string $name)
public function clearPool(string $name): bool
{
if (!isset($this->pools[$name])) {
throw new \InvalidArgumentException(sprintf('Cache pool not found: "%s".', $name));
@@ -64,9 +57,6 @@ class Psr6CacheClearer implements CacheClearerInterface
return $this->pools[$name]->clear();
}
/**
* {@inheritdoc}
*/
public function clear(string $cacheDir)
{
foreach ($this->pools as $pool) {

View File

@@ -20,11 +20,11 @@ namespace Symfony\Component\HttpKernel\CacheWarmer;
*/
class CacheWarmerAggregate implements CacheWarmerInterface
{
private $warmers;
private $debug;
private $deprecationLogsFilepath;
private $optionalsEnabled = false;
private $onlyOptionalsEnabled = false;
private iterable $warmers;
private bool $debug;
private ?string $deprecationLogsFilepath;
private bool $optionalsEnabled = false;
private bool $onlyOptionalsEnabled = false;
/**
* @param iterable<mixed, CacheWarmerInterface> $warmers
@@ -46,9 +46,6 @@ class CacheWarmerAggregate implements CacheWarmerInterface
$this->onlyOptionalsEnabled = $this->optionalsEnabled = true;
}
/**
* {@inheritdoc}
*/
public function warmUp(string $cacheDir): array
{
if ($collectDeprecations = $this->debug && !\defined('PHPUNIT_COMPOSER_INSTALL')) {
@@ -116,9 +113,6 @@ class CacheWarmerAggregate implements CacheWarmerInterface
return array_values(array_unique(array_merge([], ...$preload)));
}
/**
* {@inheritdoc}
*/
public function isOptional(): bool
{
return false;

View File

@@ -21,7 +21,7 @@ use Symfony\Component\HttpKernel\KernelInterface;
*/
class FileLocator extends BaseFileLocator
{
private $kernel;
private KernelInterface $kernel;
public function __construct(KernelInterface $kernel)
{
@@ -30,10 +30,7 @@ class FileLocator extends BaseFileLocator
parent::__construct();
}
/**
* {@inheritdoc}
*/
public function locate(string $file, string $currentPath = null, bool $first = true)
public function locate(string $file, string $currentPath = null, bool $first = true): string|array
{
if (isset($file[0]) && '@' === $file[0]) {
$resource = $this->kernel->locateResource($file);

View File

@@ -16,6 +16,7 @@ use Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolve
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestAttributeValueResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestValueResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\SessionValueResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\VariadicValueResolver;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactoryInterface;
@@ -27,11 +28,11 @@ use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactoryInter
*/
final class ArgumentResolver implements ArgumentResolverInterface
{
private $argumentMetadataFactory;
private $argumentValueResolvers;
private ArgumentMetadataFactoryInterface $argumentMetadataFactory;
private iterable $argumentValueResolvers;
/**
* @param iterable<mixed, ArgumentValueResolverInterface> $argumentValueResolvers
* @param iterable<mixed, ArgumentValueResolverInterface|ValueResolverInterface> $argumentValueResolvers
*/
public function __construct(ArgumentMetadataFactoryInterface $argumentMetadataFactory = null, iterable $argumentValueResolvers = [])
{
@@ -39,33 +40,34 @@ final class ArgumentResolver implements ArgumentResolverInterface
$this->argumentValueResolvers = $argumentValueResolvers ?: self::getDefaultArgumentValueResolvers();
}
/**
* {@inheritdoc}
*/
public function getArguments(Request $request, callable $controller): array
public function getArguments(Request $request, callable $controller, \ReflectionFunctionAbstract $reflector = null): array
{
$arguments = [];
foreach ($this->argumentMetadataFactory->createArgumentMetadata($controller) as $metadata) {
foreach ($this->argumentMetadataFactory->createArgumentMetadata($controller, $reflector) as $metadata) {
foreach ($this->argumentValueResolvers as $resolver) {
if (!$resolver->supports($request, $metadata)) {
if ((!$resolver instanceof ValueResolverInterface || $resolver instanceof TraceableValueResolver) && !$resolver->supports($request, $metadata)) {
continue;
}
$resolved = $resolver->resolve($request, $metadata);
$atLeastOne = false;
foreach ($resolved as $append) {
$atLeastOne = true;
$arguments[] = $append;
$count = 0;
foreach ($resolver->resolve($request, $metadata) as $argument) {
++$count;
$arguments[] = $argument;
}
if (!$atLeastOne) {
if (1 < $count && !$metadata->isVariadic()) {
throw new \InvalidArgumentException(sprintf('"%s::resolve()" must yield at most one value for non-variadic arguments.', get_debug_type($resolver)));
}
if ($count) {
// continue to the next controller argument
continue 2;
}
if (!$resolver instanceof ValueResolverInterface) {
throw new \InvalidArgumentException(sprintf('"%s::resolve()" must yield at least one value.', get_debug_type($resolver)));
}
// continue to the next controller argument
continue 2;
}
$representative = $controller;
@@ -73,7 +75,7 @@ final class ArgumentResolver implements ArgumentResolverInterface
if (\is_array($representative)) {
$representative = sprintf('%s::%s()', \get_class($representative[0]), $representative[1]);
} elseif (\is_object($representative)) {
$representative = \get_class($representative);
$representative = get_debug_type($representative);
}
throw new \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument. Either the argument is nullable and no null value has been provided, no default value has been provided or because there is a non optional argument after this one.', $representative, $metadata->getName()));

View File

@@ -0,0 +1,93 @@
<?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\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Attempt to resolve backed enum cases from request attributes, for a route path parameter,
* leading to a 404 Not Found if the attribute value isn't a valid backing value for the enum type.
*
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
*
* @final since Symfony 6.2
*/
class BackedEnumValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
{
/**
* @deprecated since Symfony 6.2, use resolve() instead
*/
public function supports(Request $request, ArgumentMetadata $argument): bool
{
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
if (!is_subclass_of($argument->getType(), \BackedEnum::class)) {
return false;
}
if ($argument->isVariadic()) {
// only target route path parameters, which cannot be variadic.
return false;
}
// do not support if no value can be resolved at all
// letting the \Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver be used
// or \Symfony\Component\HttpKernel\Controller\ArgumentResolver fail with a meaningful error.
return $request->attributes->has($argument->getName());
}
public function resolve(Request $request, ArgumentMetadata $argument): iterable
{
if (!is_subclass_of($argument->getType(), \BackedEnum::class)) {
return [];
}
if ($argument->isVariadic()) {
// only target route path parameters, which cannot be variadic.
return [];
}
// do not support if no value can be resolved at all
// letting the \Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver be used
// or \Symfony\Component\HttpKernel\Controller\ArgumentResolver fail with a meaningful error.
if (!$request->attributes->has($argument->getName())) {
return [];
}
$value = $request->attributes->get($argument->getName());
if (null === $value) {
return [null];
}
if ($value instanceof \BackedEnum) {
return [$value];
}
if (!\is_int($value) && !\is_string($value)) {
throw new \LogicException(sprintf('Could not resolve the "%s $%s" controller argument: expecting an int or string, got "%s".', $argument->getType(), $argument->getName(), get_debug_type($value)));
}
/** @var class-string<\BackedEnum> $enumType */
$enumType = $argument->getType();
try {
return [$enumType::from($value)];
} catch (\ValueError $e) {
throw new NotFoundHttpException(sprintf('Could not resolve the "%s $%s" controller argument: ', $argument->getType(), $argument->getName()).$e->getMessage(), $e);
}
}
}

View File

@@ -0,0 +1,86 @@
<?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\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Attribute\MapDateTime;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Convert DateTime instances from request attribute variable.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Tim Goudriaan <tim@codedmonkey.com>
*/
final class DateTimeValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
{
/**
* @deprecated since Symfony 6.2, use resolve() instead
*/
public function supports(Request $request, ArgumentMetadata $argument): bool
{
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
return is_a($argument->getType(), \DateTimeInterface::class, true) && $request->attributes->has($argument->getName());
}
public function resolve(Request $request, ArgumentMetadata $argument): array
{
if (!is_a($argument->getType(), \DateTimeInterface::class, true) || !$request->attributes->has($argument->getName())) {
return [];
}
$value = $request->attributes->get($argument->getName());
$class = \DateTimeInterface::class === $argument->getType() ? \DateTimeImmutable::class : $argument->getType();
if ($value instanceof \DateTimeInterface) {
return [$value instanceof $class ? $value : $class::createFromInterface($value)];
}
if ($argument->isNullable() && !$value) {
return [null];
}
$format = null;
if ($attributes = $argument->getAttributes(MapDateTime::class, ArgumentMetadata::IS_INSTANCEOF)) {
$attribute = $attributes[0];
$format = $attribute->format;
}
if (null !== $format) {
$date = $class::createFromFormat($format, $value);
if (($class::getLastErrors() ?: ['warning_count' => 0])['warning_count']) {
$date = false;
}
} else {
if (false !== filter_var($value, \FILTER_VALIDATE_INT, ['options' => ['min_range' => 0]])) {
$value = '@'.$value;
}
try {
$date = new $class($value ?? 'now');
} catch (\Exception) {
$date = false;
}
}
if (!$date) {
throw new NotFoundHttpException(sprintf('Invalid date given for parameter "%s".', $argument->getName()));
}
return [$date];
}
}

View File

@@ -13,6 +13,7 @@ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
/**
@@ -20,21 +21,28 @@ use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
*
* @author Iltar van der Berg <kjarli@gmail.com>
*/
final class DefaultValueResolver implements ArgumentValueResolverInterface
final class DefaultValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
{
/**
* {@inheritdoc}
* @deprecated since Symfony 6.2, use resolve() instead
*/
public function supports(Request $request, ArgumentMetadata $argument): bool
{
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
return $argument->hasDefaultValue() || (null !== $argument->getType() && $argument->isNullable() && !$argument->isVariadic());
}
/**
* {@inheritdoc}
*/
public function resolve(Request $request, ArgumentMetadata $argument): iterable
public function resolve(Request $request, ArgumentMetadata $argument): array
{
yield $argument->hasDefaultValue() ? $argument->getDefaultValue() : null;
if ($argument->hasDefaultValue()) {
return [$argument->getDefaultValue()];
}
if (null !== $argument->getType() && $argument->isNullable() && !$argument->isVariadic()) {
return [null];
}
return [];
}
}

View File

@@ -15,6 +15,7 @@ use Psr\Container\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
/**
@@ -22,9 +23,9 @@ use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
*
* @author Simeon Kolev <simeon.kolev9@gmail.com>
*/
final class NotTaggedControllerValueResolver implements ArgumentValueResolverInterface
final class NotTaggedControllerValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
{
private $container;
private ContainerInterface $container;
public function __construct(ContainerInterface $container)
{
@@ -32,10 +33,12 @@ final class NotTaggedControllerValueResolver implements ArgumentValueResolverInt
}
/**
* {@inheritdoc}
* @deprecated since Symfony 6.2, use resolve() instead
*/
public function supports(Request $request, ArgumentMetadata $argument): bool
{
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
$controller = $request->attributes->get('_controller');
if (\is_array($controller) && \is_callable($controller, true) && \is_string($controller[0])) {
@@ -55,13 +58,14 @@ final class NotTaggedControllerValueResolver implements ArgumentValueResolverInt
return false === $this->container->has($controller);
}
/**
* {@inheritdoc}
*/
public function resolve(Request $request, ArgumentMetadata $argument): iterable
public function resolve(Request $request, ArgumentMetadata $argument): array
{
if (\is_array($controller = $request->attributes->get('_controller'))) {
$controller = $request->attributes->get('_controller');
if (\is_array($controller) && \is_callable($controller, true) && \is_string($controller[0])) {
$controller = $controller[0].'::'.$controller[1];
} elseif (!\is_string($controller) || '' === $controller) {
return [];
}
if ('\\' === $controller[0]) {
@@ -74,6 +78,10 @@ final class NotTaggedControllerValueResolver implements ArgumentValueResolverInt
: $controller.'::__invoke';
}
if ($this->container->has($controller)) {
return [];
}
$what = sprintf('argument $%s of "%s()"', $argument->getName(), $controller);
$message = sprintf('Could not resolve %s, maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"?', $what);

View File

@@ -13,6 +13,7 @@ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
/**
@@ -20,21 +21,20 @@ use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
*
* @author Iltar van der Berg <kjarli@gmail.com>
*/
final class RequestAttributeValueResolver implements ArgumentValueResolverInterface
final class RequestAttributeValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
{
/**
* {@inheritdoc}
* @deprecated since Symfony 6.2, use resolve() instead
*/
public function supports(Request $request, ArgumentMetadata $argument): bool
{
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
return !$argument->isVariadic() && $request->attributes->has($argument->getName());
}
/**
* {@inheritdoc}
*/
public function resolve(Request $request, ArgumentMetadata $argument): iterable
public function resolve(Request $request, ArgumentMetadata $argument): array
{
yield $request->attributes->get($argument->getName());
return !$argument->isVariadic() && $request->attributes->has($argument->getName()) ? [$request->attributes->get($argument->getName())] : [];
}
}

View File

@@ -13,6 +13,7 @@ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
/**
@@ -20,21 +21,20 @@ use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
*
* @author Iltar van der Berg <kjarli@gmail.com>
*/
final class RequestValueResolver implements ArgumentValueResolverInterface
final class RequestValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
{
/**
* {@inheritdoc}
* @deprecated since Symfony 6.2, use resolve() instead
*/
public function supports(Request $request, ArgumentMetadata $argument): bool
{
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
return Request::class === $argument->getType() || is_subclass_of($argument->getType(), Request::class);
}
/**
* {@inheritdoc}
*/
public function resolve(Request $request, ArgumentMetadata $argument): iterable
public function resolve(Request $request, ArgumentMetadata $argument): array
{
yield $request;
return Request::class === $argument->getType() || is_subclass_of($argument->getType(), Request::class) ? [$request] : [];
}
}

View File

@@ -15,6 +15,7 @@ use Psr\Container\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
/**
@@ -22,9 +23,9 @@ use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
*
* @author Nicolas Grekas <p@tchwork.com>
*/
final class ServiceValueResolver implements ArgumentValueResolverInterface
final class ServiceValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
{
private $container;
private ContainerInterface $container;
public function __construct(ContainerInterface $container)
{
@@ -32,10 +33,12 @@ final class ServiceValueResolver implements ArgumentValueResolverInterface
}
/**
* {@inheritdoc}
* @deprecated since Symfony 6.2, use resolve() instead
*/
public function supports(Request $request, ArgumentMetadata $argument): bool
{
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
$controller = $request->attributes->get('_controller');
if (\is_array($controller) && \is_callable($controller, true) && \is_string($controller[0])) {
@@ -55,26 +58,30 @@ final class ServiceValueResolver implements ArgumentValueResolverInterface
return $this->container->has($controller) && $this->container->get($controller)->has($argument->getName());
}
/**
* {@inheritdoc}
*/
public function resolve(Request $request, ArgumentMetadata $argument): iterable
public function resolve(Request $request, ArgumentMetadata $argument): array
{
if (\is_array($controller = $request->attributes->get('_controller'))) {
$controller = $request->attributes->get('_controller');
if (\is_array($controller) && \is_callable($controller, true) && \is_string($controller[0])) {
$controller = $controller[0].'::'.$controller[1];
} elseif (!\is_string($controller) || '' === $controller) {
return [];
}
if ('\\' === $controller[0]) {
$controller = ltrim($controller, '\\');
}
if (!$this->container->has($controller)) {
$i = strrpos($controller, ':');
if (!$this->container->has($controller) && false !== $i = strrpos($controller, ':')) {
$controller = substr($controller, 0, $i).strtolower(substr($controller, $i));
}
if (!$this->container->has($controller) || !$this->container->get($controller)->has($argument->getName())) {
return [];
}
try {
yield $this->container->get($controller)->get($argument->getName());
return [$this->container->get($controller)->get($argument->getName())];
} catch (RuntimeException $e) {
$what = sprintf('argument $%s of "%s()"', $argument->getName(), $controller);
$message = preg_replace('/service "\.service_locator\.[^"]++"/', $what, $e->getMessage());
@@ -84,7 +91,6 @@ final class ServiceValueResolver implements ArgumentValueResolverInterface
}
$r = new \ReflectionProperty($e, 'message');
$r->setAccessible(true);
$r->setValue($e, $message);
throw $e;

View File

@@ -14,6 +14,7 @@ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
/**
@@ -21,13 +22,15 @@ use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
*
* @author Iltar van der Berg <kjarli@gmail.com>
*/
final class SessionValueResolver implements ArgumentValueResolverInterface
final class SessionValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
{
/**
* {@inheritdoc}
* @deprecated since Symfony 6.2, use resolve() instead
*/
public function supports(Request $request, ArgumentMetadata $argument): bool
{
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
if (!$request->hasSession()) {
return false;
}
@@ -40,11 +43,17 @@ final class SessionValueResolver implements ArgumentValueResolverInterface
return $request->getSession() instanceof $type;
}
/**
* {@inheritdoc}
*/
public function resolve(Request $request, ArgumentMetadata $argument): iterable
public function resolve(Request $request, ArgumentMetadata $argument): array
{
yield $request->getSession();
if (!$request->hasSession()) {
return [];
}
$type = $argument->getType();
if (SessionInterface::class !== $type && !is_subclass_of($type, SessionInterface::class)) {
return [];
}
return $request->getSession() instanceof $type ? [$request->getSession()] : [];
}
}

View File

@@ -13,6 +13,7 @@ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
use Symfony\Component\Stopwatch\Stopwatch;
@@ -21,22 +22,26 @@ use Symfony\Component\Stopwatch\Stopwatch;
*
* @author Iltar van der Berg <kjarli@gmail.com>
*/
final class TraceableValueResolver implements ArgumentValueResolverInterface
final class TraceableValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
{
private $inner;
private $stopwatch;
private ArgumentValueResolverInterface|ValueResolverInterface $inner;
private Stopwatch $stopwatch;
public function __construct(ArgumentValueResolverInterface $inner, Stopwatch $stopwatch)
public function __construct(ArgumentValueResolverInterface|ValueResolverInterface $inner, Stopwatch $stopwatch)
{
$this->inner = $inner;
$this->stopwatch = $stopwatch;
}
/**
* {@inheritdoc}
* @deprecated since Symfony 6.2, use resolve() instead
*/
public function supports(Request $request, ArgumentMetadata $argument): bool
{
if ($this->inner instanceof ValueResolverInterface) {
return true;
}
$method = \get_class($this->inner).'::'.__FUNCTION__;
$this->stopwatch->start($method, 'controller.argument_value_resolver');
@@ -47,9 +52,6 @@ final class TraceableValueResolver implements ArgumentValueResolverInterface
return $return;
}
/**
* {@inheritdoc}
*/
public function resolve(Request $request, ArgumentMetadata $argument): iterable
{
$method = \get_class($this->inner).'::'.__FUNCTION__;

View File

@@ -0,0 +1,53 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Uid\AbstractUid;
final class UidValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
{
/**
* @deprecated since Symfony 6.2, use resolve() instead
*/
public function supports(Request $request, ArgumentMetadata $argument): bool
{
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
return !$argument->isVariadic()
&& \is_string($request->attributes->get($argument->getName()))
&& null !== $argument->getType()
&& is_subclass_of($argument->getType(), AbstractUid::class, true);
}
public function resolve(Request $request, ArgumentMetadata $argument): array
{
if ($argument->isVariadic()
|| !\is_string($value = $request->attributes->get($argument->getName()))
|| null === ($uidClass = $argument->getType())
|| !is_subclass_of($argument->getType(), AbstractUid::class, true)
) {
return [];
}
/* @var class-string<AbstractUid> $uidClass */
try {
return [$uidClass::fromString($value)];
} catch (\InvalidArgumentException $e) {
throw new NotFoundHttpException(sprintf('The uid for the "%s" parameter is invalid.', $argument->getName()), $e);
}
}
}

View File

@@ -13,6 +13,7 @@ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
/**
@@ -20,27 +21,30 @@ use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
*
* @author Iltar van der Berg <kjarli@gmail.com>
*/
final class VariadicValueResolver implements ArgumentValueResolverInterface
final class VariadicValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
{
/**
* {@inheritdoc}
* @deprecated since Symfony 6.2, use resolve() instead
*/
public function supports(Request $request, ArgumentMetadata $argument): bool
{
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
return $argument->isVariadic() && $request->attributes->has($argument->getName());
}
/**
* {@inheritdoc}
*/
public function resolve(Request $request, ArgumentMetadata $argument): iterable
public function resolve(Request $request, ArgumentMetadata $argument): array
{
if (!$argument->isVariadic() || !$request->attributes->has($argument->getName())) {
return [];
}
$values = $request->attributes->get($argument->getName());
if (!\is_array($values)) {
throw new \InvalidArgumentException(sprintf('The action argument "...$%1$s" is required to be an array, the request attribute "%1$s" contains a type of "%2$s" instead.', $argument->getName(), get_debug_type($values)));
}
yield from $values;
return $values;
}
}

View File

@@ -24,9 +24,9 @@ interface ArgumentResolverInterface
/**
* Returns the arguments to pass to the controller.
*
* @return array
* @param \ReflectionFunctionAbstract|null $reflector
*
* @throws \RuntimeException When no value could be provided for a required argument
*/
public function getArguments(Request $request, callable $controller);
public function getArguments(Request $request, callable $controller/* , \ReflectionFunctionAbstract $reflector = null */): array;
}

View File

@@ -18,20 +18,18 @@ use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
* Responsible for resolving the value of an argument based on its metadata.
*
* @author Iltar van der Berg <kjarli@gmail.com>
*
* @deprecated since Symfony 6.2, implement ValueResolverInterface instead
*/
interface ArgumentValueResolverInterface
{
/**
* Whether this resolver can resolve the value for the given ArgumentMetadata.
*
* @return bool
*/
public function supports(Request $request, ArgumentMetadata $argument);
public function supports(Request $request, ArgumentMetadata $argument): bool;
/**
* Returns the possible value(s).
*
* @return iterable
*/
public function resolve(Request $request, ArgumentMetadata $argument);
public function resolve(Request $request, ArgumentMetadata $argument): iterable;
}

View File

@@ -32,20 +32,7 @@ class ContainerControllerResolver extends ControllerResolver
parent::__construct($logger);
}
protected function createController(string $controller)
{
if (1 === substr_count($controller, ':')) {
$controller = str_replace(':', '::', $controller);
trigger_deprecation('symfony/http-kernel', '5.1', 'Referencing controllers with a single colon is deprecated. Use "%s" instead.', $controller);
}
return parent::createController($controller);
}
/**
* {@inheritdoc}
*/
protected function instantiateController(string $class)
protected function instantiateController(string $class): object
{
$class = ltrim($class, '\\');

View File

@@ -23,22 +23,17 @@ use Symfony\Component\HttpFoundation\Request;
*/
class ControllerResolver implements ControllerResolverInterface
{
private $logger;
private ?LoggerInterface $logger;
public function __construct(LoggerInterface $logger = null)
{
$this->logger = $logger;
}
/**
* {@inheritdoc}
*/
public function getController(Request $request)
public function getController(Request $request): callable|false
{
if (!$controller = $request->attributes->get('_controller')) {
if (null !== $this->logger) {
$this->logger->warning('Unable to look for the controller as the "_controller" parameter is missing.');
}
$this->logger?->warning('Unable to look for the controller as the "_controller" parameter is missing.');
return false;
}
@@ -48,15 +43,8 @@ class ControllerResolver implements ControllerResolverInterface
try {
$controller[0] = $this->instantiateController($controller[0]);
} catch (\Error|\LogicException $e) {
try {
// We cannot just check is_callable but have to use reflection because a non-static method
// can still be called statically in PHP but we don't want that. This is deprecated in PHP 7, so we
// could simplify this with PHP 8.
if ((new \ReflectionMethod($controller[0], $controller[1]))->isStatic()) {
return $controller;
}
} catch (\ReflectionException $reflectionException) {
throw $e;
if (\is_callable($controller)) {
return $controller;
}
throw $e;
@@ -98,11 +86,9 @@ class ControllerResolver implements ControllerResolverInterface
/**
* Returns a callable for the given controller.
*
* @return callable
*
* @throws \InvalidArgumentException When the controller cannot be created
*/
protected function createController(string $controller)
protected function createController(string $controller): callable
{
if (!str_contains($controller, '::')) {
$controller = $this->instantiateController($controller);
@@ -123,7 +109,7 @@ class ControllerResolver implements ControllerResolverInterface
if ((new \ReflectionMethod($class, $method))->isStatic()) {
return $class.'::'.$method;
}
} catch (\ReflectionException $reflectionException) {
} catch (\ReflectionException) {
throw $e;
}
@@ -139,15 +125,13 @@ class ControllerResolver implements ControllerResolverInterface
/**
* Returns an instantiated controller.
*
* @return object
*/
protected function instantiateController(string $class)
protected function instantiateController(string $class): object
{
return new $class();
}
private function getControllerError($callable): string
private function getControllerError(mixed $callable): string
{
if (\is_string($callable)) {
if (str_contains($callable, '::')) {

View File

@@ -37,5 +37,5 @@ interface ControllerResolverInterface
*
* @throws \LogicException If a controller was found based on the request but it is not callable
*/
public function getController(Request $request);
public function getController(Request $request): callable|false;
}

View File

@@ -25,11 +25,11 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
*/
class ErrorController
{
private $kernel;
private $controller;
private $errorRenderer;
private HttpKernelInterface $kernel;
private string|object|array|null $controller;
private ErrorRendererInterface $errorRenderer;
public function __construct(HttpKernelInterface $kernel, $controller, ErrorRendererInterface $errorRenderer)
public function __construct(HttpKernelInterface $kernel, string|object|array|null $controller, ErrorRendererInterface $errorRenderer)
{
$this->kernel = $kernel;
$this->controller = $controller;

View File

@@ -19,8 +19,8 @@ use Symfony\Component\Stopwatch\Stopwatch;
*/
class TraceableArgumentResolver implements ArgumentResolverInterface
{
private $resolver;
private $stopwatch;
private ArgumentResolverInterface $resolver;
private Stopwatch $stopwatch;
public function __construct(ArgumentResolverInterface $resolver, Stopwatch $stopwatch)
{
@@ -29,13 +29,14 @@ class TraceableArgumentResolver implements ArgumentResolverInterface
}
/**
* {@inheritdoc}
* @param \ReflectionFunctionAbstract|null $reflector
*/
public function getArguments(Request $request, callable $controller)
public function getArguments(Request $request, callable $controller/* , \ReflectionFunctionAbstract $reflector = null */): array
{
$reflector = 2 < \func_num_args() ? func_get_arg(2) : null;
$e = $this->stopwatch->start('controller.get_arguments');
$ret = $this->resolver->getArguments($request, $controller);
$ret = $this->resolver->getArguments($request, $controller, $reflector);
$e->stop();

View File

@@ -19,8 +19,8 @@ use Symfony\Component\Stopwatch\Stopwatch;
*/
class TraceableControllerResolver implements ControllerResolverInterface
{
private $resolver;
private $stopwatch;
private ControllerResolverInterface $resolver;
private Stopwatch $stopwatch;
public function __construct(ControllerResolverInterface $resolver, Stopwatch $stopwatch)
{
@@ -28,10 +28,7 @@ class TraceableControllerResolver implements ControllerResolverInterface
$this->stopwatch = $stopwatch;
}
/**
* {@inheritdoc}
*/
public function getController(Request $request)
public function getController(Request $request): callable|false
{
$e = $this->stopwatch->start('controller.get_callable');

View File

@@ -0,0 +1,28 @@
<?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\HttpKernel\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
/**
* Responsible for resolving the value of an argument based on its metadata.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
interface ValueResolverInterface
{
/**
* Returns the possible value(s).
*/
public function resolve(Request $request, ArgumentMetadata $argument): iterable;
}

View File

@@ -11,8 +11,6 @@
namespace Symfony\Component\HttpKernel\ControllerMetadata;
use Symfony\Component\HttpKernel\Attribute\ArgumentInterface;
/**
* Responsible for storing metadata of an argument.
*
@@ -22,18 +20,18 @@ class ArgumentMetadata
{
public const IS_INSTANCEOF = 2;
private $name;
private $type;
private $isVariadic;
private $hasDefaultValue;
private $defaultValue;
private $isNullable;
private $attributes;
private string $name;
private ?string $type;
private bool $isVariadic;
private bool $hasDefaultValue;
private mixed $defaultValue;
private bool $isNullable;
private array $attributes;
/**
* @param object[] $attributes
*/
public function __construct(string $name, ?string $type, bool $isVariadic, bool $hasDefaultValue, $defaultValue, bool $isNullable = false, $attributes = [])
public function __construct(string $name, ?string $type, bool $isVariadic, bool $hasDefaultValue, mixed $defaultValue, bool $isNullable = false, array $attributes = [])
{
$this->name = $name;
$this->type = $type;
@@ -41,21 +39,13 @@ class ArgumentMetadata
$this->hasDefaultValue = $hasDefaultValue;
$this->defaultValue = $defaultValue;
$this->isNullable = $isNullable || null === $type || ($hasDefaultValue && null === $defaultValue);
if (null === $attributes || $attributes instanceof ArgumentInterface) {
trigger_deprecation('symfony/http-kernel', '5.3', 'The "%s" constructor expects an array of PHP attributes as last argument, %s given.', __CLASS__, get_debug_type($attributes));
$attributes = $attributes ? [$attributes] : [];
}
$this->attributes = $attributes;
}
/**
* Returns the name as given in PHP, $foo would yield "foo".
*
* @return string
*/
public function getName()
public function getName(): string
{
return $this->name;
}
@@ -64,20 +54,16 @@ class ArgumentMetadata
* Returns the type of the argument.
*
* The type is the PHP class in 5.5+ and additionally the basic type in PHP 7.0+.
*
* @return string|null
*/
public function getType()
public function getType(): ?string
{
return $this->type;
}
/**
* Returns whether the argument is defined as "...$variadic".
*
* @return bool
*/
public function isVariadic()
public function isVariadic(): bool
{
return $this->isVariadic;
}
@@ -86,20 +72,16 @@ class ArgumentMetadata
* Returns whether the argument has a default value.
*
* Implies whether an argument is optional.
*
* @return bool
*/
public function hasDefaultValue()
public function hasDefaultValue(): bool
{
return $this->hasDefaultValue;
}
/**
* Returns whether the argument accepts null values.
*
* @return bool
*/
public function isNullable()
public function isNullable(): bool
{
return $this->isNullable;
}
@@ -108,10 +90,8 @@ class ArgumentMetadata
* Returns the default value of the argument.
*
* @throws \LogicException if no default value is present; {@see self::hasDefaultValue()}
*
* @return mixed
*/
public function getDefaultValue()
public function getDefaultValue(): mixed
{
if (!$this->hasDefaultValue) {
throw new \LogicException(sprintf('Argument $%s does not have a default value. Use "%s::hasDefaultValue()" to avoid this exception.', $this->name, __CLASS__));
@@ -121,21 +101,10 @@ class ArgumentMetadata
}
/**
* Returns the attribute (if any) that was set on the argument.
*/
public function getAttribute(): ?ArgumentInterface
{
trigger_deprecation('symfony/http-kernel', '5.3', 'Method "%s()" is deprecated, use "getAttributes()" instead.', __METHOD__);
if (!$this->attributes) {
return null;
}
return $this->attributes[0] instanceof ArgumentInterface ? $this->attributes[0] : null;
}
/**
* @return object[]
* @param class-string $name
* @param self::IS_INSTANCEOF|0 $flags
*
* @return array<object>
*/
public function getAttributes(string $name = null, int $flags = 0): array
{
@@ -143,6 +112,19 @@ class ArgumentMetadata
return $this->attributes;
}
return $this->getAttributesOfType($name, $flags);
}
/**
* @template T of object
*
* @param class-string<T> $name
* @param self::IS_INSTANCEOF|0 $flags
*
* @return array<T>
*/
public function getAttributesOfType(string $name, int $flags = 0): array
{
$attributes = [];
if ($flags & self::IS_INSTANCEOF) {
foreach ($this->attributes as $attribute) {
@@ -152,7 +134,7 @@ class ArgumentMetadata
}
} else {
foreach ($this->attributes as $attribute) {
if (\get_class($attribute) === $name) {
if ($attribute::class === $name) {
$attributes[] = $attribute;
}
}

View File

@@ -18,37 +18,20 @@ namespace Symfony\Component\HttpKernel\ControllerMetadata;
*/
final class ArgumentMetadataFactory implements ArgumentMetadataFactoryInterface
{
/**
* {@inheritdoc}
*/
public function createArgumentMetadata($controller): array
public function createArgumentMetadata(string|object|array $controller, \ReflectionFunctionAbstract $reflector = null): array
{
$arguments = [];
$reflector ??= new \ReflectionFunction($controller(...));
if (\is_array($controller)) {
$reflection = new \ReflectionMethod($controller[0], $controller[1]);
$class = $reflection->class;
} elseif (\is_object($controller) && !$controller instanceof \Closure) {
$reflection = new \ReflectionMethod($controller, '__invoke');
$class = $reflection->class;
} else {
$reflection = new \ReflectionFunction($controller);
if ($class = str_contains($reflection->name, '{closure}') ? null : (\PHP_VERSION_ID >= 80111 ? $reflection->getClosureCalledClass() : $reflection->getClosureScopeClass())) {
$class = $class->name;
}
}
foreach ($reflection->getParameters() as $param) {
foreach ($reflector->getParameters() as $param) {
$attributes = [];
if (\PHP_VERSION_ID >= 80000) {
foreach ($param->getAttributes() as $reflectionAttribute) {
if (class_exists($reflectionAttribute->getName())) {
$attributes[] = $reflectionAttribute->newInstance();
}
foreach ($param->getAttributes() as $reflectionAttribute) {
if (class_exists($reflectionAttribute->getName())) {
$attributes[] = $reflectionAttribute->newInstance();
}
}
$arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $class), $param->isVariadic(), $param->isDefaultValueAvailable(), $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, $param->allowsNull(), $attributes);
$arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param), $param->isVariadic(), $param->isDefaultValueAvailable(), $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, $param->allowsNull(), $attributes);
}
return $arguments;
@@ -57,22 +40,17 @@ final class ArgumentMetadataFactory implements ArgumentMetadataFactoryInterface
/**
* Returns an associated type to the given parameter if available.
*/
private function getType(\ReflectionParameter $parameter, ?string $class): ?string
private function getType(\ReflectionParameter $parameter): ?string
{
if (!$type = $parameter->getType()) {
return null;
}
$name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type;
if (null !== $class) {
switch (strtolower($name)) {
case 'self':
return $class;
case 'parent':
return get_parent_class($class) ?: null;
}
}
return $name;
return match (strtolower($name)) {
'self' => $parameter->getDeclaringClass()?->name,
'parent' => get_parent_class($parameter->getDeclaringClass()?->name ?? '') ?: null,
default => $name,
};
}
}

View File

@@ -19,9 +19,9 @@ namespace Symfony\Component\HttpKernel\ControllerMetadata;
interface ArgumentMetadataFactoryInterface
{
/**
* @param string|object|array $controller The controller to resolve the arguments for
* @param \ReflectionFunctionAbstract|null $reflector
*
* @return ArgumentMetadata[]
*/
public function createArgumentMetadata($controller);
public function createArgumentMetadata(string|object|array $controller/* , \ReflectionFunctionAbstract $reflector = null */): array;
}

View File

@@ -24,26 +24,24 @@ use Symfony\Component\VarDumper\Caster\ClassStub;
*/
class ConfigDataCollector extends DataCollector implements LateDataCollectorInterface
{
/**
* @var KernelInterface
*/
private $kernel;
private KernelInterface $kernel;
/**
* Sets the Kernel associated with this Request.
*/
public function setKernel(KernelInterface $kernel = null)
{
if (1 > \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
}
$this->kernel = $kernel;
}
/**
* {@inheritdoc}
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
{
$eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE);
$eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE);
$eom = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE);
$eol = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE);
$this->data = [
'token' => $response->headers->get('X-Debug-Token'),
@@ -60,15 +58,15 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
'php_intl_locale' => class_exists(\Locale::class, false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a',
'php_timezone' => date_default_timezone_get(),
'xdebug_enabled' => \extension_loaded('xdebug'),
'apcu_enabled' => \extension_loaded('apcu') && filter_var(\ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN),
'zend_opcache_enabled' => \extension_loaded('Zend OPcache') && filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN),
'apcu_enabled' => \extension_loaded('apcu') && filter_var(\ini_get('apc.enabled'), \FILTER_VALIDATE_BOOL),
'zend_opcache_enabled' => \extension_loaded('Zend OPcache') && filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOL),
'bundles' => [],
'sapi_name' => \PHP_SAPI,
];
if (isset($this->kernel)) {
foreach ($this->kernel->getBundles() as $name => $bundle) {
$this->data['bundles'][$name] = new ClassStub(\get_class($bundle));
$this->data['bundles'][$name] = new ClassStub($bundle::class);
}
}
@@ -78,9 +76,6 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
}
}
/**
* {@inheritdoc}
*/
public function reset()
{
$this->data = [];
@@ -108,9 +103,8 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
}
/**
* Returns the state of the current Symfony release.
*
* @return string One of: unknown, dev, stable, eom, eol
* Returns the state of the current Symfony release
* as one of: unknown, dev, stable, eom, eol.
*/
public function getSymfonyState(): string
{
@@ -126,9 +120,6 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
return $this->data['symfony_minor_version'];
}
/**
* Returns if the current Symfony version is a Long-Term Support one.
*/
public function isSymfonyLts(): bool
{
return $this->data['symfony_lts'];
@@ -168,9 +159,6 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
return $this->data['php_version_extra'] ?? null;
}
/**
* @return int The PHP architecture as number of bits (e.g. 32 or 64)
*/
public function getPhpArchitecture(): int
{
return $this->data['php_architecture'];
@@ -199,19 +187,27 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
*
* @return bool|string true if debug is enabled, false otherwise or a string if no kernel was set
*/
public function isDebug()
public function isDebug(): bool|string
{
return $this->data['debug'];
}
/**
* Returns true if the XDebug is enabled.
* Returns true if the Xdebug is enabled.
*/
public function hasXDebug(): bool
public function hasXdebug(): bool
{
return $this->data['xdebug_enabled'];
}
/**
* Returns true if the function xdebug_info is available.
*/
public function hasXdebugInfo(): bool
{
return \function_exists('xdebug_info');
}
/**
* Returns true if APCu is enabled.
*/
@@ -241,24 +237,16 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
return $this->data['sapi_name'];
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'config';
}
/**
* Tries to retrieve information about the current Symfony version.
*
* @return string One of: dev, stable, eom, eol
*/
private function determineSymfonyState(): string
{
$now = new \DateTime();
$eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE)->modify('last day of this month');
$eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE)->modify('last day of this month');
$now = new \DateTimeImmutable();
$eom = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE)->modify('last day of this month');
$eol = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE)->modify('last day of this month');
if ($now > $eol) {
$versionState = 'eol';

View File

@@ -33,27 +33,20 @@ abstract class DataCollector implements DataCollectorInterface
*/
protected $data = [];
/**
* @var ClonerInterface
*/
private $cloner;
private ClonerInterface $cloner;
/**
* Converts the variable into a serializable Data instance.
*
* This array can be displayed in the template using
* the VarDumper component.
*
* @param mixed $var
*
* @return Data
*/
protected function cloneVar($var)
protected function cloneVar(mixed $var): Data
{
if ($var instanceof Data) {
return $var;
}
if (null === $this->cloner) {
if (!isset($this->cloner)) {
$this->cloner = new VarCloner();
$this->cloner->setMaxItems(-1);
$this->cloner->addCasters($this->getCasters());
@@ -84,10 +77,7 @@ abstract class DataCollector implements DataCollectorInterface
return $casters;
}
/**
* @return array
*/
public function __sleep()
public function __sleep(): array
{
return ['data'];
}
@@ -106,7 +96,7 @@ abstract class DataCollector implements DataCollectorInterface
/**
* @internal to prevent implementing \Serializable
*/
final protected function unserialize($data)
final protected function unserialize(string $data)
{
}
}

View File

@@ -31,23 +31,19 @@ use Symfony\Component\VarDumper\Server\Connection;
*/
class DumpDataCollector extends DataCollector implements DataDumperInterface
{
private $stopwatch;
private $fileLinkFormat;
private $dataCount = 0;
private $isCollected = true;
private $clonesCount = 0;
private $clonesIndex = 0;
private $rootRefs;
private $charset;
private $requestStack;
private $dumper;
private $sourceContextProvider;
private ?Stopwatch $stopwatch = null;
private string|FileLinkFormatter|false $fileLinkFormat;
private int $dataCount = 0;
private bool $isCollected = true;
private int $clonesCount = 0;
private int $clonesIndex = 0;
private array $rootRefs;
private string $charset;
private ?RequestStack $requestStack;
private DataDumperInterface|Connection|null $dumper;
private mixed $sourceContextProvider;
/**
* @param string|FileLinkFormatter|null $fileLinkFormat
* @param DataDumperInterface|Connection|null $dumper
*/
public function __construct(Stopwatch $stopwatch = null, $fileLinkFormat = null, string $charset = null, RequestStack $requestStack = null, $dumper = null)
public function __construct(Stopwatch $stopwatch = null, string|FileLinkFormatter $fileLinkFormat = null, string $charset = null, RequestStack $requestStack = null, DataDumperInterface|Connection $dumper = null)
{
$fileLinkFormat = $fileLinkFormat ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
$this->stopwatch = $stopwatch;
@@ -74,9 +70,7 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
public function dump(Data $data)
{
if ($this->stopwatch) {
$this->stopwatch->start('dump');
}
$this->stopwatch?->start('dump');
['name' => $name, 'file' => $file, 'line' => $line, 'file_excerpt' => $fileExcerpt] = $this->sourceContextProvider->getContext();
@@ -96,9 +90,7 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
$this->data[] = compact('data', 'name', 'file', 'line', 'fileExcerpt');
++$this->dataCount;
if ($this->stopwatch) {
$this->stopwatch->stop('dump');
}
$this->stopwatch?->stop('dump');
}
public function collect(Request $request, Response $response, \Throwable $exception = null)
@@ -138,9 +130,7 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
public function reset()
{
if ($this->stopwatch) {
$this->stopwatch->reset();
}
$this->stopwatch?->reset();
$this->data = [];
$this->dataCount = 0;
$this->isCollected = true;

View File

@@ -22,13 +22,15 @@ use Symfony\Contracts\Service\ResetInterface;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @see TraceableEventDispatcher
*
* @final
*/
class EventDataCollector extends DataCollector implements LateDataCollectorInterface
{
protected $dispatcher;
private $requestStack;
private $currentRequest;
private ?EventDispatcherInterface $dispatcher;
private ?RequestStack $requestStack;
private ?Request $currentRequest = null;
public function __construct(EventDispatcherInterface $dispatcher = null, RequestStack $requestStack = null)
{
@@ -36,9 +38,6 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
$this->requestStack = $requestStack;
}
/**
* {@inheritdoc}
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
{
$this->currentRequest = $this->requestStack && $this->requestStack->getMainRequest() !== $request ? $request : null;
@@ -70,8 +69,6 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
}
/**
* @param array $listeners An array of called listeners
*
* @see TraceableEventDispatcher
*/
public function setCalledListeners(array $listeners)
@@ -81,10 +78,8 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
/**
* @see TraceableEventDispatcher
*
* @return array|Data
*/
public function getCalledListeners()
public function getCalledListeners(): array|Data
{
return $this->data['called_listeners'];
}
@@ -99,10 +94,8 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
/**
* @see TraceableEventDispatcher
*
* @return array|Data
*/
public function getNotCalledListeners()
public function getNotCalledListeners(): array|Data
{
return $this->data['not_called_listeners'];
}
@@ -119,17 +112,12 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
/**
* @see TraceableEventDispatcher
*
* @return array|Data
*/
public function getOrphanedEvents()
public function getOrphanedEvents(): array|Data
{
return $this->data['orphaned_events'];
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'events';

View File

@@ -22,9 +22,6 @@ use Symfony\Component\HttpFoundation\Response;
*/
class ExceptionDataCollector extends DataCollector
{
/**
* {@inheritdoc}
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
{
if (null !== $exception) {
@@ -34,9 +31,6 @@ class ExceptionDataCollector extends DataCollector
}
}
/**
* {@inheritdoc}
*/
public function reset()
{
$this->data = [];
@@ -47,10 +41,7 @@ class ExceptionDataCollector extends DataCollector
return isset($this->data['exception']);
}
/**
* @return \Exception|FlattenException
*/
public function getException()
public function getException(): \Exception|FlattenException
{
return $this->data['exception'];
}
@@ -75,9 +66,6 @@ class ExceptionDataCollector extends DataCollector
return $this->data['exception']->getTrace();
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'exception';

View File

@@ -24,15 +24,15 @@ use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
*/
class LoggerDataCollector extends DataCollector implements LateDataCollectorInterface
{
private $logger;
private $containerPathPrefix;
private $currentRequest;
private $requestStack;
private $processedLogs;
private DebugLoggerInterface $logger;
private ?string $containerPathPrefix;
private ?Request $currentRequest = null;
private ?RequestStack $requestStack;
private ?array $processedLogs = null;
public function __construct(object $logger = null, string $containerPathPrefix = null, RequestStack $requestStack = null)
{
if (null !== $logger && $logger instanceof DebugLoggerInterface) {
if ($logger instanceof DebugLoggerInterface) {
$this->logger = $logger;
}
@@ -40,31 +40,22 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
$this->requestStack = $requestStack;
}
/**
* {@inheritdoc}
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
{
$this->currentRequest = $this->requestStack && $this->requestStack->getMainRequest() !== $request ? $request : null;
}
/**
* {@inheritdoc}
*/
public function reset()
{
if ($this->logger instanceof DebugLoggerInterface) {
if (isset($this->logger)) {
$this->logger->clear();
}
$this->data = [];
}
/**
* {@inheritdoc}
*/
public function lateCollect()
{
if (null !== $this->logger) {
if (isset($this->logger)) {
$containerDeprecationLogs = $this->getContainerDeprecationLogs();
$this->data = $this->computeErrorsCount($containerDeprecationLogs);
// get compiler logs later (only when they are needed) to improve performance
@@ -187,9 +178,6 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
return $this->cloneVar($this->getContainerCompilerLogs($this->data['compiler_logs_filepath'] ?? null));
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'logger';

View File

@@ -26,17 +26,11 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte
$this->reset();
}
/**
* {@inheritdoc}
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
{
$this->updateMemoryUsage();
}
/**
* {@inheritdoc}
*/
public function reset()
{
$this->data = [
@@ -45,9 +39,6 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte
];
}
/**
* {@inheritdoc}
*/
public function lateCollect()
{
$this->updateMemoryUsage();
@@ -58,10 +49,7 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte
return $this->data['memory'];
}
/**
* @return int|float
*/
public function getMemoryLimit()
public function getMemoryLimit(): int|float
{
return $this->data['memory_limit'];
}
@@ -71,18 +59,12 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte
$this->data['memory'] = memory_get_peak_usage(true);
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'memory';
}
/**
* @return int|float
*/
private function convertToBytes(string $memoryLimit)
private function convertToBytes(string $memoryLimit): int|float
{
if ('-1' === $memoryLimit) {
return -1;
@@ -100,11 +82,11 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte
switch (substr($memoryLimit, -1)) {
case 't': $max *= 1024;
// no break
// no break
case 'g': $max *= 1024;
// no break
// no break
case 'm': $max *= 1024;
// no break
// no break
case 'k': $max *= 1024;
}

View File

@@ -34,9 +34,9 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
/**
* @var \SplObjectStorage<Request, callable>
*/
private $controllers;
private $sessionUsages = [];
private $requestStack;
private \SplObjectStorage $controllers;
private array $sessionUsages = [];
private ?RequestStack $requestStack;
public function __construct(RequestStack $requestStack = null)
{
@@ -44,9 +44,6 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
$this->requestStack = $requestStack;
}
/**
* {@inheritdoc}
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
{
// attributes are serialized and as they can be anything, they need to be converted to strings.
@@ -110,7 +107,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
'session_metadata' => $sessionMetadata,
'session_attributes' => $sessionAttributes,
'session_usages' => array_values($this->sessionUsages),
'stateless_check' => $this->requestStack && ($mainRequest = $this->requestStack->getMainRequest()) && $mainRequest->attributes->get('_stateless', false),
'stateless_check' => $this->requestStack?->getMainRequest()?->attributes->get('_stateless') ?? false,
'flashes' => $flashes,
'path_info' => $request->getPathInfo(),
'controller' => 'n/a',
@@ -346,7 +343,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
* @return array|string|Data The controller as a string or array of data
* with keys 'class', 'method', 'file' and 'line'
*/
public function getController()
public function getController(): array|string|Data
{
return $this->data['controller'];
}
@@ -357,7 +354,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
* @return array|Data|false A legacy array of data from the previous redirection response
* or false otherwise
*/
public function getRedirect()
public function getRedirect(): array|Data|false
{
return $this->data['redirect'] ?? false;
}
@@ -391,9 +388,6 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
];
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'request';
@@ -431,11 +425,9 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
}
/**
* @param string|object|array|null $controller The controller to parse
*
* @return array|string An array of controller data or a simple string
*/
private function parseController($controller)
private function parseController(array|object|string|null $controller): array|string
{
if (\is_string($controller) && str_contains($controller, '::')) {
$controller = explode('::', $controller);
@@ -451,7 +443,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
'file' => $r->getFileName(),
'line' => $r->getStartLine(),
];
} catch (\ReflectionException $e) {
} catch (\ReflectionException) {
if (\is_callable($controller)) {
// using __call or __callStatic
return [

View File

@@ -32,8 +32,6 @@ class RouterDataCollector extends DataCollector
}
/**
* {@inheritdoc}
*
* @final
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
@@ -61,7 +59,7 @@ class RouterDataCollector extends DataCollector
];
}
protected function guessRoute(Request $request, $controller)
protected function guessRoute(Request $request, string|object|array $controller)
{
return 'n/a';
}
@@ -77,31 +75,22 @@ class RouterDataCollector extends DataCollector
/**
* @return bool Whether this request will result in a redirect
*/
public function getRedirect()
public function getRedirect(): bool
{
return $this->data['redirect'];
}
/**
* @return string|null
*/
public function getTargetUrl()
public function getTargetUrl(): ?string
{
return $this->data['url'];
}
/**
* @return string|null
*/
public function getTargetRoute()
public function getTargetRoute(): ?string
{
return $this->data['route'];
}
/**
* {@inheritdoc}
*/
public function getName()
public function getName(): string
{
return 'router';
}

View File

@@ -24,8 +24,8 @@ use Symfony\Component\Stopwatch\StopwatchEvent;
*/
class TimeDataCollector extends DataCollector implements LateDataCollectorInterface
{
private $kernel;
private $stopwatch;
private ?KernelInterface $kernel;
private ?Stopwatch $stopwatch;
public function __construct(KernelInterface $kernel = null, Stopwatch $stopwatch = null)
{
@@ -33,9 +33,6 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
$this->stopwatch = $stopwatch;
}
/**
* {@inheritdoc}
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
{
if (null !== $this->kernel) {
@@ -52,21 +49,13 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
];
}
/**
* {@inheritdoc}
*/
public function reset()
{
$this->data = [];
if (null !== $this->stopwatch) {
$this->stopwatch->reset();
}
$this->stopwatch?->reset();
}
/**
* {@inheritdoc}
*/
public function lateCollect()
{
if (null !== $this->stopwatch && isset($this->data['token'])) {
@@ -133,9 +122,6 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
return $this->data['stopwatch_installed'];
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'time';

View File

@@ -11,6 +11,7 @@
namespace Symfony\Component\HttpKernel\Debug;
use Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRendererInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
@@ -24,28 +25,19 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
*/
class FileLinkFormatter
{
private const FORMATS = [
'textmate' => 'txmt://open?url=file://%f&line=%l',
'macvim' => 'mvim://open?url=file://%f&line=%l',
'emacs' => 'emacs://open?url=file://%f&line=%l',
'sublime' => 'subl://open?url=file://%f&line=%l',
'phpstorm' => 'phpstorm://open?file=%f&line=%l',
'atom' => 'atom://core/open/file?filename=%f&line=%l',
'vscode' => 'vscode://file/%f:%l',
];
private $fileLinkFormat;
private $requestStack;
private $baseDir;
private $urlFormat;
private array|false $fileLinkFormat;
private ?RequestStack $requestStack = null;
private ?string $baseDir = null;
private \Closure|string|null $urlFormat;
/**
* @param string|array|null $fileLinkFormat
* @param string|\Closure $urlFormat the URL format, or a closure that returns it on-demand
* @param string|\Closure $urlFormat the URL format, or a closure that returns it on-demand
*/
public function __construct($fileLinkFormat = null, RequestStack $requestStack = null, string $baseDir = null, $urlFormat = null)
public function __construct(string|array $fileLinkFormat = null, RequestStack $requestStack = null, string $baseDir = null, string|\Closure $urlFormat = null)
{
if (!\is_array($fileLinkFormat) && $fileLinkFormat = (self::FORMATS[$fileLinkFormat] ?? $fileLinkFormat) ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format')) {
$fileLinkFormat ??= $_ENV['SYMFONY_IDE'] ?? $_SERVER['SYMFONY_IDE'] ?? '';
if (!\is_array($fileLinkFormat) && $fileLinkFormat = (ErrorRendererInterface::IDE_LINK_FORMATS[$fileLinkFormat] ?? $fileLinkFormat) ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format') ?: false) {
$i = strpos($f = $fileLinkFormat, '&', max(strrpos($f, '%f'), strrpos($f, '%l'))) ?: \strlen($f);
$fileLinkFormat = [substr($f, 0, $i)] + preg_split('/&([^>]++)>/', substr($f, $i), -1, \PREG_SPLIT_DELIM_CAPTURE);
}
@@ -89,12 +81,12 @@ class FileLinkFormatter
{
try {
return $router->generate($routeName).$queryString;
} catch (\Throwable $e) {
} catch (\Throwable) {
return null;
}
}
private function getFileLinkFormat()
private function getFileLinkFormat(): array|false
{
if ($this->fileLinkFormat) {
return $this->fileLinkFormat;
@@ -111,6 +103,6 @@ class FileLinkFormatter
}
}
return null;
return false;
}
}

View File

@@ -23,9 +23,6 @@ use Symfony\Component\HttpKernel\KernelEvents;
*/
class TraceableEventDispatcher extends BaseTraceableEventDispatcher
{
/**
* {@inheritdoc}
*/
protected function beforeDispatch(string $eventName, object $event)
{
switch ($eventName) {
@@ -52,15 +49,12 @@ class TraceableEventDispatcher extends BaseTraceableEventDispatcher
// which must be caught.
try {
$this->stopwatch->openSection($sectionId);
} catch (\LogicException $e) {
} catch (\LogicException) {
}
break;
}
}
/**
* {@inheritdoc}
*/
protected function afterDispatch(string $eventName, object $event)
{
switch ($eventName) {
@@ -83,7 +77,7 @@ class TraceableEventDispatcher extends BaseTraceableEventDispatcher
}
try {
$this->stopwatch->stopSection($sectionId);
} catch (\LogicException $e) {
} catch (\LogicException) {
}
break;
}

View File

@@ -12,7 +12,6 @@
namespace Symfony\Component\HttpKernel\DependencyInjection;
use Composer\Autoload\ClassLoader;
use Symfony\Component\Debug\DebugClassLoader as LegacyDebugClassLoader;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\ErrorHandler\DebugClassLoader;
@@ -25,16 +24,13 @@ use Symfony\Component\HttpKernel\Kernel;
*/
class AddAnnotatedClassesToCachePass implements CompilerPassInterface
{
private $kernel;
private Kernel $kernel;
public function __construct(Kernel $kernel)
{
$this->kernel = $kernel;
}
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
$annotatedClasses = [];
@@ -93,7 +89,7 @@ class AddAnnotatedClassesToCachePass implements CompilerPassInterface
continue;
}
if ($function[0] instanceof DebugClassLoader || $function[0] instanceof LegacyDebugClassLoader) {
if ($function[0] instanceof DebugClassLoader) {
$function = $function[0]->getClassLoader();
}
@@ -117,7 +113,7 @@ class AddAnnotatedClassesToCachePass implements CompilerPassInterface
$regex = strtr($regex, ['\\*\\*' => '.*?', '\\*' => '[^\\\\]*?']);
// If this class does not end by a slash, anchor the end
if ('\\' !== substr($regex, -1)) {
if (!str_ends_with($regex, '\\')) {
$regex .= '$';
}

View File

@@ -27,9 +27,6 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
*/
abstract class ConfigurableExtension extends Extension
{
/**
* {@inheritdoc}
*/
final public function load(array $configs, ContainerBuilder $container)
{
$this->loadInternal($this->processConfiguration($this->getConfiguration($configs, $container), $configs), $container);

View File

@@ -28,40 +28,25 @@ class ControllerArgumentValueResolverPass implements CompilerPassInterface
{
use PriorityTaggedServiceTrait;
private $argumentResolverService;
private $argumentValueResolverTag;
private $traceableResolverStopwatch;
public function __construct(string $argumentResolverService = 'argument_resolver', string $argumentValueResolverTag = 'controller.argument_value_resolver', string $traceableResolverStopwatch = 'debug.stopwatch')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->argumentResolverService = $argumentResolverService;
$this->argumentValueResolverTag = $argumentValueResolverTag;
$this->traceableResolverStopwatch = $traceableResolverStopwatch;
}
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition($this->argumentResolverService)) {
if (!$container->hasDefinition('argument_resolver')) {
return;
}
$resolvers = $this->findAndSortTaggedServices($this->argumentValueResolverTag, $container);
$resolvers = $this->findAndSortTaggedServices('controller.argument_value_resolver', $container);
if ($container->getParameter('kernel.debug') && class_exists(Stopwatch::class) && $container->has($this->traceableResolverStopwatch)) {
if ($container->getParameter('kernel.debug') && class_exists(Stopwatch::class) && $container->has('debug.stopwatch')) {
foreach ($resolvers as $resolverReference) {
$id = (string) $resolverReference;
$container->register("debug.$id", TraceableValueResolver::class)
->setDecoratedService($id)
->setArguments([new Reference("debug.$id.inner"), new Reference($this->traceableResolverStopwatch)]);
->setArguments([new Reference("debug.$id.inner"), new Reference('debug.stopwatch')]);
}
}
$container
->getDefinition($this->argumentResolverService)
->getDefinition('argument_resolver')
->replaceArgument(1, new IteratorArgument($resolvers))
;
}

View File

@@ -20,14 +20,12 @@ use Symfony\Component\DependencyInjection\Extension\Extension as BaseExtension;
*/
abstract class Extension extends BaseExtension
{
private $annotatedClasses = [];
private array $annotatedClasses = [];
/**
* Gets the annotated classes to cache.
*
* @return array
*/
public function getAnnotatedClassesToCompile()
public function getAnnotatedClassesToCompile(): array
{
return $this->annotatedClasses;
}

View File

@@ -25,28 +25,15 @@ use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface;
*/
class FragmentRendererPass implements CompilerPassInterface
{
private $handlerService;
private $rendererTag;
public function __construct(string $handlerService = 'fragment.handler', string $rendererTag = 'kernel.fragment_renderer')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->handlerService = $handlerService;
$this->rendererTag = $rendererTag;
}
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition($this->handlerService)) {
if (!$container->hasDefinition('fragment.handler')) {
return;
}
$definition = $container->getDefinition($this->handlerService);
$definition = $container->getDefinition('fragment.handler');
$renderers = [];
foreach ($container->findTaggedServiceIds($this->rendererTag, true) as $id => $tags) {
foreach ($container->findTaggedServiceIds('kernel.fragment_renderer', true) as $id => $tags) {
$def = $container->getDefinition($id);
$class = $container->getParameterBag()->resolveValue($def->getClass());

View File

@@ -13,6 +13,7 @@ namespace Symfony\Component\HttpKernel\DependencyInjection;
use Psr\Container\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Controller\ControllerReference;
use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
/**
@@ -22,12 +23,12 @@ use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
*/
class LazyLoadingFragmentHandler extends FragmentHandler
{
private $container;
private ContainerInterface $container;
/**
* @var array<string, bool>
*/
private $initialized = [];
private array $initialized = [];
public function __construct(ContainerInterface $container, RequestStack $requestStack, bool $debug = false)
{
@@ -36,10 +37,7 @@ class LazyLoadingFragmentHandler extends FragmentHandler
parent::__construct($requestStack, [], $debug);
}
/**
* {@inheritdoc}
*/
public function render($uri, string $renderer = 'inline', array $options = [])
public function render(string|ControllerReference $uri, string $renderer = 'inline', array $options = []): ?string
{
if (!isset($this->initialized[$renderer]) && $this->container->has($renderer)) {
$this->addRenderer($this->container->get($renderer));

View File

@@ -14,6 +14,8 @@ namespace Symfony\Component\HttpKernel\DependencyInjection;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Log\Logger;
/**
@@ -23,9 +25,6 @@ use Symfony\Component\HttpKernel\Log\Logger;
*/
class LoggerPass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
$container->setAlias(LoggerInterface::class, 'logger')
@@ -36,6 +35,7 @@ class LoggerPass implements CompilerPassInterface
}
$container->register('logger', Logger::class)
->setArguments([null, null, null, new Reference(RequestStack::class)])
->setPublic(false);
}
}

View File

@@ -21,7 +21,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
*/
class MergeExtensionConfigurationPass extends BaseMergeExtensionConfigurationPass
{
private $extensions;
private array $extensions;
/**
* @param string[] $extensions

View File

@@ -11,21 +11,20 @@
namespace Symfony\Component\HttpKernel\DependencyInjection;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\DependencyInjection\Attribute\Target;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\LazyProxy\ProxyHelper;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\TypedReference;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\VarExporter\ProxyHelper;
/**
* Creates the service-locators required by ServiceValueResolver.
@@ -34,26 +33,9 @@ use Symfony\Component\HttpFoundation\Session\SessionInterface;
*/
class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
{
private $resolverServiceId;
private $controllerTag;
private $controllerLocator;
private $notTaggedControllerResolverServiceId;
public function __construct(string $resolverServiceId = 'argument_resolver.service', string $controllerTag = 'controller.service_arguments', string $controllerLocator = 'argument_resolver.controller_locator', string $notTaggedControllerResolverServiceId = 'argument_resolver.not_tagged_controller')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->resolverServiceId = $resolverServiceId;
$this->controllerTag = $controllerTag;
$this->controllerLocator = $controllerLocator;
$this->notTaggedControllerResolverServiceId = $notTaggedControllerResolverServiceId;
}
public function process(ContainerBuilder $container)
{
if (false === $container->hasDefinition($this->resolverServiceId) && false === $container->hasDefinition($this->notTaggedControllerResolverServiceId)) {
if (!$container->hasDefinition('argument_resolver.service') && !$container->hasDefinition('argument_resolver.not_tagged_controller')) {
return;
}
@@ -67,7 +49,9 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
}
}
foreach ($container->findTaggedServiceIds($this->controllerTag, true) as $id => $tags) {
$emptyAutowireAttributes = class_exists(Autowire::class) ? null : [];
foreach ($container->findTaggedServiceIds('controller.service_arguments', true) as $id => $tags) {
$def = $container->getDefinition($id);
$def->setPublic(true);
$class = $def->getClass();
@@ -85,13 +69,12 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
if (!$r = $container->getReflectionClass($class)) {
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
}
$isContainerAware = $r->implementsInterface(ContainerAwareInterface::class) || is_subclass_of($class, AbstractController::class);
// get regular public methods
$methods = [];
$arguments = [];
foreach ($r->getMethods(\ReflectionMethod::IS_PUBLIC) as $r) {
if ('setContainer' === $r->name && $isContainerAware) {
if ('setContainer' === $r->name) {
continue;
}
if (!$r->isConstructor() && !$r->isDestructor() && !$r->isAbstract()) {
@@ -107,11 +90,11 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
}
foreach (['action', 'argument', 'id'] as $k) {
if (!isset($attributes[$k][0])) {
throw new InvalidArgumentException(sprintf('Missing "%s" attribute on tag "%s" %s for service "%s".', $k, $this->controllerTag, json_encode($attributes, \JSON_UNESCAPED_UNICODE), $id));
throw new InvalidArgumentException(sprintf('Missing "%s" attribute on tag "controller.service_arguments" %s for service "%s".', $k, json_encode($attributes, \JSON_UNESCAPED_UNICODE), $id));
}
}
if (!isset($methods[$action = strtolower($attributes['action'])])) {
throw new InvalidArgumentException(sprintf('Invalid "action" attribute on tag "%s" for service "%s": no public "%s()" method found on class "%s".', $this->controllerTag, $id, $attributes['action'], $class));
throw new InvalidArgumentException(sprintf('Invalid "action" attribute on tag "controller.service_arguments" for service "%s": no public "%s()" method found on class "%s".', $id, $attributes['action'], $class));
}
[$r, $parameters] = $methods[$action];
$found = false;
@@ -127,7 +110,7 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
}
if (!$found) {
throw new InvalidArgumentException(sprintf('Invalid "%s" tag for service "%s": method "%s()" has no "%s" argument on class "%s".', $this->controllerTag, $id, $r->name, $attributes['argument'], $class));
throw new InvalidArgumentException(sprintf('Invalid "controller.service_arguments" tag for service "%s": method "%s()" has no "%s" argument on class "%s".', $id, $r->name, $attributes['argument'], $class));
}
}
@@ -138,15 +121,16 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
$args = [];
foreach ($parameters as $p) {
/** @var \ReflectionParameter $p */
$type = ltrim($target = (string) ProxyHelper::getTypeHint($r, $p), '\\');
$type = preg_replace('/(^|[(|&])\\\\/', '\1', $target = ltrim(ProxyHelper::exportType($p) ?? '', '?'));
$invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
$autowireAttributes = $autowire ? $emptyAutowireAttributes : [];
if (isset($arguments[$r->name][$p->name])) {
$target = $arguments[$r->name][$p->name];
if ('?' !== $target[0]) {
$invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE;
} elseif ('' === $target = (string) substr($target, 1)) {
throw new InvalidArgumentException(sprintf('A "%s" tag must have non-empty "id" attributes for service "%s".', $this->controllerTag, $id));
throw new InvalidArgumentException(sprintf('A "controller.service_arguments" tag must have non-empty "id" attributes for service "%s".', $id));
} elseif ($p->allowsNull() && !$p->isOptional()) {
$invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE;
}
@@ -156,17 +140,10 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
[$bindingValue, $bindingId, , $bindingType, $bindingFile] = $binding->getValues();
$binding->setValues([$bindingValue, $bindingId, true, $bindingType, $bindingFile]);
if (!$bindingValue instanceof Reference) {
$args[$p->name] = new Reference('.value.'.$container->hash($bindingValue));
$container->register((string) $args[$p->name], 'mixed')
->setFactory('current')
->addArgument([$bindingValue]);
} else {
$args[$p->name] = $bindingValue;
}
$args[$p->name] = $bindingValue;
continue;
} elseif (!$type || !$autowire || '\\' !== $target[0]) {
} elseif (!$autowire || (!($autowireAttributes ??= $p->getAttributes(Autowire::class)) && (!$type || '\\' !== $target[0]))) {
continue;
} elseif (is_subclass_of($type, \UnitEnum::class)) {
// do not attempt to register enum typed arguments if not already present in bindings
@@ -179,6 +156,21 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
continue;
}
if ($autowireAttributes) {
$value = $autowireAttributes[0]->newInstance()->value;
if ($value instanceof Reference) {
$args[$p->name] = $type ? new TypedReference($value, $type, $invalidBehavior, $p->name) : new Reference($value, $invalidBehavior);
} else {
$args[$p->name] = new Reference('.value.'.$container->hash($value));
$container->register((string) $args[$p->name], 'mixed')
->setFactory('current')
->addArgument([$value]);
}
continue;
}
if ($type && !$p->isOptional() && !$p->allowsNull() && !class_exists($type) && !interface_exists($type, false)) {
$message = sprintf('Cannot determine controller argument for "%s::%s()": the $%s argument is type-hinted with the non-existent class or interface: "%s".', $class, $r->name, $p->name, $type);
@@ -192,7 +184,7 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
$args[$p->name] = new Reference($erroredId, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE);
} else {
$target = ltrim($target, '\\');
$target = preg_replace('/(^|[(|&])\\\\/', '\1', $target);
$args[$p->name] = $type ? new TypedReference($target, $type, $invalidBehavior, Target::parseName($p)) : new Reference($target, $invalidBehavior);
}
}
@@ -209,16 +201,16 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
$controllerLocatorRef = ServiceLocatorTagPass::register($container, $controllers);
if ($container->hasDefinition($this->resolverServiceId)) {
$container->getDefinition($this->resolverServiceId)
if ($container->hasDefinition('argument_resolver.service')) {
$container->getDefinition('argument_resolver.service')
->replaceArgument(0, $controllerLocatorRef);
}
if ($container->hasDefinition($this->notTaggedControllerResolverServiceId)) {
$container->getDefinition($this->notTaggedControllerResolverServiceId)
if ($container->hasDefinition('argument_resolver.not_tagged_controller')) {
$container->getDefinition('argument_resolver.not_tagged_controller')
->replaceArgument(0, $controllerLocatorRef);
}
$container->setAlias($this->controllerLocator, (string) $controllerLocatorRef);
$container->setAlias('argument_resolver.controller_locator', (string) $controllerLocatorRef);
}
}

View File

@@ -23,39 +23,26 @@ use Symfony\Component\DependencyInjection\Reference;
*/
class RegisterLocaleAwareServicesPass implements CompilerPassInterface
{
private $listenerServiceId;
private $localeAwareTag;
public function __construct(string $listenerServiceId = 'locale_aware_listener', string $localeAwareTag = 'kernel.locale_aware')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->listenerServiceId = $listenerServiceId;
$this->localeAwareTag = $localeAwareTag;
}
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition($this->listenerServiceId)) {
if (!$container->hasDefinition('locale_aware_listener')) {
return;
}
$services = [];
foreach ($container->findTaggedServiceIds($this->localeAwareTag) as $id => $tags) {
foreach ($container->findTaggedServiceIds('kernel.locale_aware') as $id => $tags) {
$services[] = new Reference($id);
}
if (!$services) {
$container->removeDefinition($this->listenerServiceId);
$container->removeDefinition('locale_aware_listener');
return;
}
$container
->getDefinition($this->listenerServiceId)
->getDefinition('locale_aware_listener')
->setArgument(0, new IteratorArgument($services))
;
}

View File

@@ -21,20 +21,9 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
*/
class RemoveEmptyControllerArgumentLocatorsPass implements CompilerPassInterface
{
private $controllerLocator;
public function __construct(string $controllerLocator = 'argument_resolver.controller_locator')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->controllerLocator = $controllerLocator;
}
public function process(ContainerBuilder $container)
{
$controllerLocator = $container->findDefinition($this->controllerLocator);
$controllerLocator = $container->findDefinition('argument_resolver.controller_locator');
$controllers = $controllerLocator->getArgument(0);
foreach ($controllers as $controller => $argumentRef) {

View File

@@ -23,20 +23,6 @@ use Symfony\Component\DependencyInjection\Reference;
*/
class ResettableServicePass implements CompilerPassInterface
{
private $tagName;
public function __construct(string $tagName = 'kernel.reset')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->tagName = $tagName;
}
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
if (!$container->has('services_resetter')) {
@@ -45,12 +31,12 @@ class ResettableServicePass implements CompilerPassInterface
$services = $methods = [];
foreach ($container->findTaggedServiceIds($this->tagName, true) as $id => $tags) {
foreach ($container->findTaggedServiceIds('kernel.reset', true) as $id => $tags) {
$services[$id] = new Reference($id, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE);
foreach ($tags as $attributes) {
if (!isset($attributes['method'])) {
throw new RuntimeException(sprintf('Tag "%s" requires the "method" attribute to be set.', $this->tagName));
throw new RuntimeException(sprintf('Tag "kernel.reset" requires the "method" attribute to be set on service "%s".', $id));
}
if (!isset($methods[$id])) {

View File

@@ -23,8 +23,8 @@ use Symfony\Contracts\Service\ResetInterface;
*/
class ServicesResetter implements ResetInterface
{
private $resettableServices;
private $resetMethods;
private \Traversable $resettableServices;
private array $resetMethods;
/**
* @param \Traversable<string, object> $resettableServices

View File

@@ -28,25 +28,34 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
*/
final class ControllerArgumentsEvent extends KernelEvent
{
private $controller;
private $arguments;
private ControllerEvent $controllerEvent;
private array $arguments;
private array $namedArguments;
public function __construct(HttpKernelInterface $kernel, callable $controller, array $arguments, Request $request, ?int $requestType)
public function __construct(HttpKernelInterface $kernel, callable|ControllerEvent $controller, array $arguments, Request $request, ?int $requestType)
{
parent::__construct($kernel, $request, $requestType);
$this->controller = $controller;
if (!$controller instanceof ControllerEvent) {
$controller = new ControllerEvent($kernel, $controller, $request, $requestType);
}
$this->controllerEvent = $controller;
$this->arguments = $arguments;
}
public function getController(): callable
{
return $this->controller;
return $this->controllerEvent->getController();
}
public function setController(callable $controller)
/**
* @param array<class-string, list<object>>|null $attributes
*/
public function setController(callable $controller, array $attributes = null): void
{
$this->controller = $controller;
$this->controllerEvent->setController($controller, $attributes);
unset($this->namedArguments);
}
public function getArguments(): array
@@ -57,5 +66,38 @@ final class ControllerArgumentsEvent extends KernelEvent
public function setArguments(array $arguments)
{
$this->arguments = $arguments;
unset($this->namedArguments);
}
public function getNamedArguments(): array
{
if (isset($this->namedArguments)) {
return $this->namedArguments;
}
$namedArguments = [];
$arguments = $this->arguments;
foreach ($this->controllerEvent->getControllerReflector()->getParameters() as $i => $param) {
if ($param->isVariadic()) {
$namedArguments[$param->name] = \array_slice($arguments, $i);
break;
}
if (\array_key_exists($i, $arguments)) {
$namedArguments[$param->name] = $arguments[$i];
} elseif ($param->isDefaultvalueAvailable()) {
$namedArguments[$param->name] = $param->getDefaultValue();
}
}
return $this->namedArguments = $namedArguments;
}
/**
* @return array<class-string, list<object>>
*/
public function getAttributes(): array
{
return $this->controllerEvent->getAttributes();
}
}

View File

@@ -27,7 +27,9 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
*/
final class ControllerEvent extends KernelEvent
{
private $controller;
private string|array|object $controller;
private \ReflectionFunctionAbstract $controllerReflector;
private array $attributes;
public function __construct(HttpKernelInterface $kernel, callable $controller, Request $request, ?int $requestType)
{
@@ -41,8 +43,65 @@ final class ControllerEvent extends KernelEvent
return $this->controller;
}
public function setController(callable $controller): void
public function getControllerReflector(): \ReflectionFunctionAbstract
{
return $this->controllerReflector;
}
/**
* @param array<class-string, list<object>>|null $attributes
*/
public function setController(callable $controller, array $attributes = null): void
{
if (null !== $attributes) {
$this->attributes = $attributes;
}
if (isset($this->controller) && ($controller instanceof \Closure ? $controller == $this->controller : $controller === $this->controller)) {
$this->controller = $controller;
return;
}
if (null === $attributes) {
unset($this->attributes);
}
if (\is_array($controller) && method_exists(...$controller)) {
$this->controllerReflector = new \ReflectionMethod(...$controller);
} elseif (\is_string($controller) && false !== $i = strpos($controller, '::')) {
$this->controllerReflector = new \ReflectionMethod($controller);
} else {
$this->controllerReflector = new \ReflectionFunction($controller(...));
}
$this->controller = $controller;
}
/**
* @return array<class-string, list<object>>
*/
public function getAttributes(): array
{
if (isset($this->attributes)) {
return $this->attributes;
}
if (\is_array($this->controller) && method_exists(...$this->controller)) {
$class = new \ReflectionClass($this->controller[0]);
} elseif (\is_string($this->controller) && false !== $i = strpos($this->controller, '::')) {
$class = new \ReflectionClass(substr($this->controller, 0, $i));
} else {
$class = str_contains($this->controllerReflector->name, '{closure}') ? null : (\PHP_VERSION_ID >= 80111 ? $this->controllerReflector->getClosureCalledClass() : $this->controllerReflector->getClosureScopeClass());
}
$this->attributes = [];
foreach (array_merge($class?->getAttributes() ?? [], $this->controllerReflector->getAttributes()) as $attribute) {
if (class_exists($attribute->getName())) {
$this->attributes[$attribute->getName()][] = $attribute->newInstance();
}
}
return $this->attributes;
}
}

View File

@@ -29,12 +29,8 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
*/
final class ExceptionEvent extends RequestEvent
{
private $throwable;
/**
* @var bool
*/
private $allowCustomResponseCode = false;
private \Throwable $throwable;
private bool $allowCustomResponseCode = false;
public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, \Throwable $e)
{

View File

@@ -22,9 +22,9 @@ use Symfony\Contracts\EventDispatcher\Event;
*/
class KernelEvent extends Event
{
private $kernel;
private $request;
private $requestType;
private HttpKernelInterface $kernel;
private Request $request;
private ?int $requestType;
/**
* @param int $requestType The request type the kernel is currently processing; one of
@@ -39,20 +39,16 @@ class KernelEvent extends Event
/**
* Returns the kernel in which this event was thrown.
*
* @return HttpKernelInterface
*/
public function getKernel()
public function getKernel(): HttpKernelInterface
{
return $this->kernel;
}
/**
* Returns the request the kernel is currently processing.
*
* @return Request
*/
public function getRequest()
public function getRequest(): Request
{
return $this->request;
}
@@ -63,7 +59,7 @@ class KernelEvent extends Event
* @return int One of HttpKernelInterface::MAIN_REQUEST and
* HttpKernelInterface::SUB_REQUEST
*/
public function getRequestType()
public function getRequestType(): int
{
return $this->requestType;
}
@@ -75,18 +71,4 @@ class KernelEvent extends Event
{
return HttpKernelInterface::MAIN_REQUEST === $this->requestType;
}
/**
* Checks if this is a master request.
*
* @return bool
*
* @deprecated since symfony/http-kernel 5.3, use isMainRequest() instead
*/
public function isMasterRequest()
{
trigger_deprecation('symfony/http-kernel', '5.3', '"%s()" is deprecated, use "isMainRequest()" instead.', __METHOD__);
return $this->isMainRequest();
}
}

View File

@@ -24,14 +24,12 @@ use Symfony\Component\HttpFoundation\Response;
*/
class RequestEvent extends KernelEvent
{
private $response;
private ?Response $response = null;
/**
* Returns the response object.
*
* @return Response|null
*/
public function getResponse()
public function getResponse(): ?Response
{
return $this->response;
}
@@ -48,10 +46,8 @@ class RequestEvent extends KernelEvent
/**
* Returns whether a response was set.
*
* @return bool
*/
public function hasResponse()
public function hasResponse(): bool
{
return null !== $this->response;
}

View File

@@ -26,7 +26,7 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
*/
final class ResponseEvent extends KernelEvent
{
private $response;
private Response $response;
public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, Response $response)
{

View File

@@ -25,7 +25,7 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
*/
final class TerminateEvent extends KernelEvent
{
private $response;
private Response $response;
public function __construct(HttpKernelInterface $kernel, Request $request, Response $response)
{

View File

@@ -25,36 +25,23 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
*/
final class ViewEvent extends RequestEvent
{
/**
* The return value of the controller.
*
* @var mixed
*/
private $controllerResult;
public readonly ?ControllerArgumentsEvent $controllerArgumentsEvent;
private mixed $controllerResult;
public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, $controllerResult)
public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, mixed $controllerResult, ControllerArgumentsEvent $controllerArgumentsEvent = null)
{
parent::__construct($kernel, $request, $requestType);
$this->controllerResult = $controllerResult;
$this->controllerArgumentsEvent = $controllerArgumentsEvent;
}
/**
* Returns the return value of the controller.
*
* @return mixed
*/
public function getControllerResult()
public function getControllerResult(): mixed
{
return $this->controllerResult;
}
/**
* Assigns the return value of the controller.
*
* @param mixed $controllerResult The controller return value
*/
public function setControllerResult($controllerResult): void
public function setControllerResult(mixed $controllerResult): void
{
$this->controllerResult = $controllerResult;
}

View File

@@ -17,7 +17,6 @@ use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpFoundation\Session\SessionUtils;
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\Exception\UnexpectedSessionUsageException;
@@ -44,8 +43,7 @@ abstract class AbstractSessionListener implements EventSubscriberInterface, Rese
public const NO_AUTO_CACHE_CONTROL_HEADER = 'Symfony-Session-NoAutoCacheControl';
protected $container;
private $sessionUsageStack = [];
private $debug;
private bool $debug;
/**
* @var array<string, mixed>
@@ -88,9 +86,6 @@ abstract class AbstractSessionListener implements EventSubscriberInterface, Rese
return $sess;
});
}
$session = $this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : null;
$this->sessionUsageStack[] = $session instanceof Session ? $session->getUsageIndex() : 0;
}
public function onKernelResponse(ResponseEvent $event)
@@ -103,10 +98,10 @@ abstract class AbstractSessionListener implements EventSubscriberInterface, Rese
$autoCacheControl = !$response->headers->has(self::NO_AUTO_CACHE_CONTROL_HEADER);
// Always remove the internal header if present
$response->headers->remove(self::NO_AUTO_CACHE_CONTROL_HEADER);
if (!$session = $this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : ($event->getRequest()->hasSession() ? $event->getRequest()->getSession() : null)) {
if (!$event->getRequest()->hasSession(true)) {
return;
}
$session = $event->getRequest()->getSession();
if ($session->isStarted()) {
/*
@@ -156,7 +151,7 @@ abstract class AbstractSessionListener implements EventSubscriberInterface, Rese
$request = $event->getRequest();
$requestSessionCookieId = $request->cookies->get($sessionName);
$isSessionEmpty = $session->isEmpty() && empty($_SESSION); // checking $_SESSION to keep compatibility with native sessions
$isSessionEmpty = ($session instanceof Session ? $session->isEmpty() : !$session->all()) && empty($_SESSION); // checking $_SESSION to keep compatibility with native sessions
if ($requestSessionCookieId && $isSessionEmpty) {
// PHP internally sets the session cookie value to "deleted" when setcookie() is called with empty string $value argument
// which happens in \Symfony\Component\HttpFoundation\Session\Storage\Handler\AbstractSessionHandler::destroy
@@ -195,7 +190,7 @@ abstract class AbstractSessionListener implements EventSubscriberInterface, Rese
}
}
if ($session instanceof Session ? $session->getUsageIndex() === end($this->sessionUsageStack) : !$session->isStarted()) {
if ($session instanceof Session ? 0 === $session->getUsageIndex() : !$session->isStarted()) {
return;
}
@@ -221,24 +216,17 @@ abstract class AbstractSessionListener implements EventSubscriberInterface, Rese
}
}
public function onFinishRequest(FinishRequestEvent $event)
{
if ($event->isMainRequest()) {
array_pop($this->sessionUsageStack);
}
}
public function onSessionUsage(): void
{
if (!$this->debug) {
return;
}
if ($this->container && $this->container->has('session_collector')) {
if ($this->container?->has('session_collector')) {
$this->container->get('session_collector')();
}
if (!$requestStack = $this->container && $this->container->has('request_stack') ? $this->container->get('request_stack') : null) {
if (!$requestStack = $this->container?->has('request_stack') ? $this->container->get('request_stack') : null) {
return;
}
@@ -252,7 +240,7 @@ abstract class AbstractSessionListener implements EventSubscriberInterface, Rese
return;
}
if (!$session = $this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : $requestStack->getCurrentRequest()->getSession()) {
if (!$session = $requestStack->getCurrentRequest()->getSession()) {
return;
}
@@ -267,9 +255,8 @@ abstract class AbstractSessionListener implements EventSubscriberInterface, Rese
{
return [
KernelEvents::REQUEST => ['onKernelRequest', 128],
// low priority to come after regular response listeners, but higher than StreamedResponseListener
// low priority to come after regular response listeners
KernelEvents::RESPONSE => ['onKernelResponse', -1000],
KernelEvents::FINISH_REQUEST => ['onFinishRequest'],
];
}
@@ -289,10 +276,8 @@ abstract class AbstractSessionListener implements EventSubscriberInterface, Rese
/**
* Gets the session object.
*
* @return SessionInterface|null
*/
abstract protected function getSession();
abstract protected function getSession(): ?SessionInterface;
private function getSessionOptions(array $sessionOptions): array
{

View File

@@ -1,120 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
trigger_deprecation('symfony/http-kernel', '5.4', '"%s" is deprecated use "%s" instead.', AbstractTestSessionListener::class, AbstractSessionListener::class);
/**
* TestSessionListener.
*
* Saves session in test environment.
*
* @author Bulat Shakirzyanov <mallluhuct@gmail.com>
* @author Fabien Potencier <fabien@symfony.com>
*
* @internal
*
* @deprecated since Symfony 5.4, use AbstractSessionListener instead
*/
abstract class AbstractTestSessionListener implements EventSubscriberInterface
{
private $sessionId;
private $sessionOptions;
public function __construct(array $sessionOptions = [])
{
$this->sessionOptions = $sessionOptions;
}
public function onKernelRequest(RequestEvent $event)
{
if (!$event->isMainRequest()) {
return;
}
// bootstrap the session
if ($event->getRequest()->hasSession()) {
$session = $event->getRequest()->getSession();
} elseif (!$session = $this->getSession()) {
return;
}
$cookies = $event->getRequest()->cookies;
if ($cookies->has($session->getName())) {
$this->sessionId = $cookies->get($session->getName());
$session->setId($this->sessionId);
}
}
/**
* Checks if session was initialized and saves if current request is the main request
* Runs on 'kernel.response' in test environment.
*/
public function onKernelResponse(ResponseEvent $event)
{
if (!$event->isMainRequest()) {
return;
}
$request = $event->getRequest();
if (!$request->hasSession()) {
return;
}
$session = $request->getSession();
if ($wasStarted = $session->isStarted()) {
$session->save();
}
if ($session instanceof Session ? !$session->isEmpty() || (null !== $this->sessionId && $session->getId() !== $this->sessionId) : $wasStarted) {
$params = session_get_cookie_params() + ['samesite' => null];
foreach ($this->sessionOptions as $k => $v) {
if (str_starts_with($k, 'cookie_')) {
$params[substr($k, 7)] = $v;
}
}
foreach ($event->getResponse()->headers->getCookies() as $cookie) {
if ($session->getName() === $cookie->getName() && $params['path'] === $cookie->getPath() && $params['domain'] == $cookie->getDomain()) {
return;
}
}
$event->getResponse()->headers->setCookie(new Cookie($session->getName(), $session->getId(), 0 === $params['lifetime'] ? 0 : time() + $params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly'], false, $params['samesite'] ?: null));
$this->sessionId = $session->getId();
}
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => ['onKernelRequest', 127], // AFTER SessionListener
KernelEvents::RESPONSE => ['onKernelResponse', -128],
];
}
/**
* Gets the session object.
*
* @return SessionInterface|null
*/
abstract protected function getSession();
}

View File

@@ -24,7 +24,7 @@ use Symfony\Component\HttpKernel\KernelEvents;
*/
class AddRequestFormatsListener implements EventSubscriberInterface
{
protected $formats;
private array $formats;
public function __construct(array $formats)
{
@@ -42,9 +42,6 @@ class AddRequestFormatsListener implements EventSubscriberInterface
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array
{
return [KernelEvents::REQUEST => ['onKernelRequest', 100]];

View File

@@ -0,0 +1,193 @@
<?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\HttpKernel\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\Cache;
use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* Handles HTTP cache headers configured via the Cache attribute.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class CacheAttributeListener implements EventSubscriberInterface
{
/**
* @var \SplObjectStorage<Request, \DateTimeInterface>
*/
private \SplObjectStorage $lastModified;
/**
* @var \SplObjectStorage<Request, string>
*/
private \SplObjectStorage $etags;
public function __construct(
private ?ExpressionLanguage $expressionLanguage = null,
) {
$this->lastModified = new \SplObjectStorage();
$this->etags = new \SplObjectStorage();
}
/**
* Handles HTTP validation headers.
*/
public function onKernelControllerArguments(ControllerArgumentsEvent $event)
{
$request = $event->getRequest();
if (!\is_array($attributes = $request->attributes->get('_cache') ?? $event->getAttributes()[Cache::class] ?? null)) {
return;
}
$request->attributes->set('_cache', $attributes);
$response = null;
$lastModified = null;
$etag = null;
/** @var Cache[] $attributes */
foreach ($attributes as $cache) {
if (null !== $cache->lastModified) {
$lastModified = $this->getExpressionLanguage()->evaluate($cache->lastModified, array_merge($request->attributes->all(), $event->getNamedArguments()));
($response ??= new Response())->setLastModified($lastModified);
}
if (null !== $cache->etag) {
$etag = hash('sha256', $this->getExpressionLanguage()->evaluate($cache->etag, array_merge($request->attributes->all(), $event->getNamedArguments())));
($response ??= new Response())->setEtag($etag);
}
}
if ($response?->isNotModified($request)) {
$event->setController(static fn () => $response);
$event->stopPropagation();
return;
}
if (null !== $etag) {
$this->etags[$request] = $etag;
}
if (null !== $lastModified) {
$this->lastModified[$request] = $lastModified;
}
}
/**
* Modifies the response to apply HTTP cache headers when needed.
*/
public function onKernelResponse(ResponseEvent $event)
{
$request = $event->getRequest();
/** @var Cache[] $attributes */
if (!\is_array($attributes = $request->attributes->get('_cache'))) {
return;
}
$response = $event->getResponse();
// http://tools.ietf.org/html/draft-ietf-httpbis-p4-conditional-12#section-3.1
if (!\in_array($response->getStatusCode(), [200, 203, 300, 301, 302, 304, 404, 410])) {
unset($this->lastModified[$request]);
unset($this->etags[$request]);
return;
}
if (isset($this->lastModified[$request]) && !$response->headers->has('Last-Modified')) {
$response->setLastModified($this->lastModified[$request]);
}
if (isset($this->etags[$request]) && !$response->headers->has('Etag')) {
$response->setEtag($this->etags[$request]);
}
unset($this->lastModified[$request]);
unset($this->etags[$request]);
$hasVary = $response->headers->has('Vary');
foreach (array_reverse($attributes) as $cache) {
if (null !== $cache->smaxage && !$response->headers->hasCacheControlDirective('s-maxage')) {
$response->setSharedMaxAge($this->toSeconds($cache->smaxage));
}
if ($cache->mustRevalidate) {
$response->headers->addCacheControlDirective('must-revalidate');
}
if (null !== $cache->maxage && !$response->headers->hasCacheControlDirective('max-age')) {
$response->setMaxAge($this->toSeconds($cache->maxage));
}
if (null !== $cache->maxStale && !$response->headers->hasCacheControlDirective('max-stale')) {
$response->headers->addCacheControlDirective('max-stale', $this->toSeconds($cache->maxStale));
}
if (null !== $cache->staleWhileRevalidate && !$response->headers->hasCacheControlDirective('stale-while-revalidate')) {
$response->headers->addCacheControlDirective('stale-while-revalidate', $this->toSeconds($cache->staleWhileRevalidate));
}
if (null !== $cache->staleIfError && !$response->headers->hasCacheControlDirective('stale-if-error')) {
$response->headers->addCacheControlDirective('stale-if-error', $this->toSeconds($cache->staleIfError));
}
if (null !== $cache->expires && !$response->headers->has('Expires')) {
$response->setExpires(new \DateTimeImmutable('@'.strtotime($cache->expires, time())));
}
if (!$hasVary && $cache->vary) {
$response->setVary($cache->vary, false);
}
}
foreach ($attributes as $cache) {
if (true === $cache->public) {
$response->setPublic();
}
if (false === $cache->public) {
$response->setPrivate();
}
}
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::CONTROLLER_ARGUMENTS => ['onKernelControllerArguments', 10],
KernelEvents::RESPONSE => ['onKernelResponse', -10],
];
}
private function getExpressionLanguage(): ExpressionLanguage
{
return $this->expressionLanguage ??= class_exists(ExpressionLanguage::class)
? new ExpressionLanguage()
: throw new \LogicException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed. Try running "composer require symfony/expression-language".');
}
private function toSeconds(int|string $time): int
{
if (!is_numeric($time)) {
$now = time();
$time = strtotime($time, $now) - $now;
}
return $time;
}
}

View File

@@ -27,20 +27,20 @@ use Symfony\Component\HttpKernel\KernelEvents;
*
* @final
*
* @internal since Symfony 5.3
* @internal
*/
class DebugHandlersListener implements EventSubscriberInterface
{
private $earlyHandler;
private $exceptionHandler;
private $logger;
private $deprecationLogger;
private $levels;
private $throwAt;
private $scream;
private $scope;
private $firstCall = true;
private $hasTerminatedWithException;
private string|object|null $earlyHandler;
private ?\Closure $exceptionHandler;
private ?LoggerInterface $logger;
private ?LoggerInterface $deprecationLogger;
private array|int|null $levels;
private ?int $throwAt;
private bool $scream;
private bool $scope;
private bool $firstCall = true;
private bool $hasTerminatedWithException = false;
/**
* @param callable|null $exceptionHandler A handler that must support \Throwable instances that will be called on Exception
@@ -49,19 +49,13 @@ class DebugHandlersListener implements EventSubscriberInterface
* @param bool $scream Enables/disables screaming mode, where even silenced errors are logged
* @param bool $scope Enables/disables scoping mode
*/
public function __construct(callable $exceptionHandler = null, LoggerInterface $logger = null, $levels = \E_ALL, ?int $throwAt = \E_ALL, bool $scream = true, $scope = true, $deprecationLogger = null, $fileLinkFormat = null)
public function __construct(callable $exceptionHandler = null, LoggerInterface $logger = null, array|int|null $levels = \E_ALL, ?int $throwAt = \E_ALL, bool $scream = true, bool $scope = true, LoggerInterface $deprecationLogger = null)
{
if (!\is_bool($scope)) {
trigger_deprecation('symfony/http-kernel', '5.4', 'Passing a $fileLinkFormat is deprecated.');
$scope = $deprecationLogger;
$deprecationLogger = $fileLinkFormat;
}
$handler = set_exception_handler('is_int');
$this->earlyHandler = \is_array($handler) ? $handler[0] : null;
restore_exception_handler();
$this->exceptionHandler = $exceptionHandler;
$this->exceptionHandler = null === $exceptionHandler ? null : $exceptionHandler(...);
$this->logger = $logger;
$this->levels = $levels ?? \E_ALL;
$this->throwAt = \is_int($throwAt) ? $throwAt : (null === $throwAt ? null : ($throwAt ? \E_ALL : null));

View File

@@ -31,10 +31,7 @@ class DisallowRobotsIndexingListener implements EventSubscriberInterface
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents()
public static function getSubscribedEvents(): array
{
return [
KernelEvents::RESPONSE => ['onResponse', -255],

View File

@@ -25,9 +25,9 @@ use Symfony\Component\VarDumper\VarDumper;
*/
class DumpListener implements EventSubscriberInterface
{
private $cloner;
private $dumper;
private $connection;
private ClonerInterface $cloner;
private DataDumperInterface $dumper;
private ?Connection $connection;
public function __construct(ClonerInterface $cloner, DataDumperInterface $dumper, Connection $connection = null)
{
@@ -51,7 +51,7 @@ class DumpListener implements EventSubscriberInterface
});
}
public static function getSubscribedEvents()
public static function getSubscribedEvents(): array
{
if (!class_exists(ConsoleEvents::class)) {
return [];

View File

@@ -12,7 +12,6 @@
namespace Symfony\Component\HttpKernel\EventListener;
use Psr\Log\LoggerInterface;
use Symfony\Component\Debug\Exception\FlattenException as LegacyFlattenException;
use Symfony\Component\ErrorHandler\Exception\FlattenException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
@@ -41,7 +40,7 @@ class ErrorListener implements EventSubscriberInterface
/**
* @param array<class-string, array{log_level: string|null, status_code: int<100,599>|null}> $exceptionsMapping
*/
public function __construct($controller, LoggerInterface $logger = null, bool $debug = false, array $exceptionsMapping = [])
public function __construct(string|object|array|null $controller, LoggerInterface $logger = null, bool $debug = false, array $exceptionsMapping = [])
{
$this->controller = $controller;
$this->logger = $logger;
@@ -102,7 +101,6 @@ class ErrorListener implements EventSubscriberInterface
} while ($prev = $wrapper->getPrevious());
$prev = new \ReflectionProperty($wrapper instanceof \Exception ? \Exception::class : \Error::class, 'previous');
$prev->setAccessible(true);
$prev->setValue($wrapper, $throwable);
throw $e;
@@ -130,10 +128,10 @@ class ErrorListener implements EventSubscriberInterface
return;
}
$r = new \ReflectionFunction(\Closure::fromCallable($event->getController()));
$r = new \ReflectionFunction($event->getController()(...));
$r = $r->getParameters()[$k] ?? null;
if ($r && (!($r = $r->getType()) instanceof \ReflectionNamedType || \in_array($r->getName(), [FlattenException::class, LegacyFlattenException::class], true))) {
if ($r && (!($r = $r->getType()) instanceof \ReflectionNamedType || FlattenException::class === $r->getName())) {
$arguments = $event->getArguments();
$arguments[$k] = FlattenException::createFromThrowable($e);
$event->setArguments($arguments);

View File

@@ -33,8 +33,8 @@ use Symfony\Component\HttpKernel\UriSigner;
*/
class FragmentListener implements EventSubscriberInterface
{
private $signer;
private $fragmentPath;
private UriSigner $signer;
private string $fragmentPath;
/**
* @param string $fragmentPath The path that triggers this listener

View File

@@ -25,8 +25,8 @@ use Symfony\Contracts\Translation\LocaleAwareInterface;
*/
class LocaleAwareListener implements EventSubscriberInterface
{
private $localeAwareServices;
private $requestStack;
private iterable $localeAwareServices;
private RequestStack $requestStack;
/**
* @param iterable<mixed, LocaleAwareInterface> $localeAwareServices
@@ -55,7 +55,7 @@ class LocaleAwareListener implements EventSubscriberInterface
$this->setLocale($parentRequest->getLocale(), $parentRequest->getDefaultLocale());
}
public static function getSubscribedEvents()
public static function getSubscribedEvents(): array
{
return [
// must be registered after the Locale listener
@@ -69,7 +69,7 @@ class LocaleAwareListener implements EventSubscriberInterface
foreach ($this->localeAwareServices as $service) {
try {
$service->setLocale($locale);
} catch (\InvalidArgumentException $e) {
} catch (\InvalidArgumentException) {
$service->setLocale($defaultLocale);
}
}

View File

@@ -29,11 +29,11 @@ use Symfony\Component\Routing\RequestContextAwareInterface;
*/
class LocaleListener implements EventSubscriberInterface
{
private $router;
private $defaultLocale;
private $requestStack;
private $useAcceptLanguageHeader;
private $enabledLocales;
private ?RequestContextAwareInterface $router;
private string $defaultLocale;
private RequestStack $requestStack;
private bool $useAcceptLanguageHeader;
private array $enabledLocales;
public function __construct(RequestStack $requestStack, string $defaultLocale = 'en', RequestContextAwareInterface $router = null, bool $useAcceptLanguageHeader = false, array $enabledLocales = [])
{
@@ -68,17 +68,17 @@ class LocaleListener implements EventSubscriberInterface
{
if ($locale = $request->attributes->get('_locale')) {
$request->setLocale($locale);
} elseif ($this->useAcceptLanguageHeader && $this->enabledLocales && ($preferredLanguage = $request->getPreferredLanguage($this->enabledLocales))) {
$request->setLocale($preferredLanguage);
} elseif ($this->useAcceptLanguageHeader) {
if ($preferredLanguage = $request->getPreferredLanguage($this->enabledLocales)) {
$request->setLocale($preferredLanguage);
}
$request->attributes->set('_vary_by_language', true);
}
}
private function setRouterContext(Request $request)
{
if (null !== $this->router) {
$this->router->getContext()->setParameter('_locale', $request->getLocale());
}
$this->router?->getContext()->setParameter('_locale', $request->getLocale());
}
public static function getSubscribedEvents(): array

View File

@@ -32,17 +32,17 @@ use Symfony\Component\HttpKernel\Profiler\Profiler;
*/
class ProfilerListener implements EventSubscriberInterface
{
protected $profiler;
protected $matcher;
protected $onlyException;
protected $onlyMainRequests;
protected $exception;
private Profiler $profiler;
private ?RequestMatcherInterface $matcher;
private bool $onlyException;
private bool $onlyMainRequests;
private ?\Throwable $exception = null;
/** @var \SplObjectStorage<Request, Profile> */
protected $profiles;
protected $requestStack;
protected $collectParameter;
private \SplObjectStorage $profiles;
private RequestStack $requestStack;
private ?string $collectParameter;
/** @var \SplObjectStorage<Request, Request|null> */
protected $parents;
private \SplObjectStorage $parents;
/**
* @param bool $onlyException True if the profiler only collects data when an exception occurs, false otherwise
@@ -87,7 +87,7 @@ class ProfilerListener implements EventSubscriberInterface
$request = $event->getRequest();
if (null !== $this->collectParameter && null !== $collectParameterValue = $request->get($this->collectParameter)) {
true === $collectParameterValue || filter_var($collectParameterValue, \FILTER_VALIDATE_BOOLEAN) ? $this->profiler->enable() : $this->profiler->disable();
true === $collectParameterValue || filter_var($collectParameterValue, \FILTER_VALIDATE_BOOL) ? $this->profiler->enable() : $this->profiler->disable();
}
$exception = $this->exception;
@@ -97,7 +97,7 @@ class ProfilerListener implements EventSubscriberInterface
return;
}
$session = $request->hasPreviousSession() && $request->hasSession() ? $request->getSession() : null;
$session = $request->hasPreviousSession() ? $request->getSession() : null;
if ($session instanceof Session) {
$usageIndexValue = $usageIndexReference = &$session->getUsageIndex();

View File

@@ -24,8 +24,8 @@ use Symfony\Component\HttpKernel\KernelEvents;
*/
class ResponseListener implements EventSubscriberInterface
{
private $charset;
private $addContentLanguageHeader;
private string $charset;
private bool $addContentLanguageHeader;
public function __construct(string $charset, bool $addContentLanguageHeader = false)
{

View File

@@ -42,25 +42,20 @@ use Symfony\Component\Routing\RequestContextAwareInterface;
*/
class RouterListener implements EventSubscriberInterface
{
private $matcher;
private $context;
private $logger;
private $requestStack;
private $projectDir;
private $debug;
private RequestMatcherInterface|UrlMatcherInterface $matcher;
private RequestContext $context;
private ?LoggerInterface $logger;
private RequestStack $requestStack;
private ?string $projectDir;
private bool $debug;
/**
* @param UrlMatcherInterface|RequestMatcherInterface $matcher The Url or Request matcher
* @param RequestContext|null $context The RequestContext (can be null when $matcher implements RequestContextAwareInterface)
* @param RequestContext|null $context The RequestContext (can be null when $matcher implements RequestContextAwareInterface)
*
* @throws \InvalidArgumentException
*/
public function __construct($matcher, RequestStack $requestStack, RequestContext $context = null, LoggerInterface $logger = null, string $projectDir = null, bool $debug = true)
public function __construct(UrlMatcherInterface|RequestMatcherInterface $matcher, RequestStack $requestStack, RequestContext $context = null, LoggerInterface $logger = null, string $projectDir = null, bool $debug = true)
{
if (!$matcher instanceof UrlMatcherInterface && !$matcher instanceof RequestMatcherInterface) {
throw new \InvalidArgumentException('Matcher must either implement UrlMatcherInterface or RequestMatcherInterface.');
}
if (null === $context && !$matcher instanceof RequestContextAwareInterface) {
throw new \InvalidArgumentException('You must either pass a RequestContext or the matcher must implement RequestContextAwareInterface.');
}
@@ -73,7 +68,7 @@ class RouterListener implements EventSubscriberInterface
$this->debug = $debug;
}
private function setCurrentRequest(Request $request = null)
private function setCurrentRequest(?Request $request)
{
if (null !== $request) {
try {
@@ -88,7 +83,7 @@ class RouterListener implements EventSubscriberInterface
* After a sub-request is done, we need to reset the routing context to the parent request so that the URL generator
* operates on the correct context again.
*/
public function onKernelFinishRequest(FinishRequestEvent $event)
public function onKernelFinishRequest()
{
$this->setCurrentRequest($this->requestStack->getParentRequest());
}
@@ -113,14 +108,12 @@ class RouterListener implements EventSubscriberInterface
$parameters = $this->matcher->match($request->getPathInfo());
}
if (null !== $this->logger) {
$this->logger->info('Matched route "{route}".', [
'route' => $parameters['_route'] ?? 'n/a',
'route_parameters' => $parameters,
'request_uri' => $request->getUri(),
'method' => $request->getMethod(),
]);
}
$this->logger?->info('Matched route "{route}".', [
'route' => $parameters['_route'] ?? 'n/a',
'route_parameters' => $parameters,
'request_uri' => $request->getUri(),
'method' => $request->getMethod(),
]);
$request->attributes->add($parameters);
unset($parameters['_route'], $parameters['_controller']);

View File

@@ -12,45 +12,18 @@
namespace Symfony\Component\HttpKernel\EventListener;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Symfony\Component\HttpKernel\Event\RequestEvent;
/**
* Sets the session in the request.
*
* When the passed container contains a "session_storage" entry which
* holds a NativeSessionStorage instance, the "cookie_secure" option
* will be set to true whenever the current main request is secure.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final
*/
class SessionListener extends AbstractSessionListener
{
public function onKernelRequest(RequestEvent $event)
{
parent::onKernelRequest($event);
if (!$event->isMainRequest() || (!$this->container->has('session') && !$this->container->has('session_factory'))) {
return;
}
if ($this->container->has('session_storage')
&& ($storage = $this->container->get('session_storage')) instanceof NativeSessionStorage
&& ($mainRequest = $this->container->get('request_stack')->getMainRequest())
&& $mainRequest->isSecure()
) {
$storage->setOptions(['cookie_secure' => true]);
}
}
protected function getSession(): ?SessionInterface
{
if ($this->container->has('session')) {
return $this->container->get('session');
}
if ($this->container->has('session_factory')) {
return $this->container->get('session_factory')->createSession();
}

View File

@@ -16,6 +16,8 @@ use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
trigger_deprecation('symfony/http-kernel', '6.1', 'The "%s" class is deprecated.', StreamedResponseListener::class);
/**
* StreamedResponseListener is responsible for sending the Response
* to the client.
@@ -23,6 +25,8 @@ use Symfony\Component\HttpKernel\KernelEvents;
* @author Fabien Potencier <fabien@symfony.com>
*
* @final
*
* @deprecated since Symfony 6.1
*/
class StreamedResponseListener implements EventSubscriberInterface
{

View File

@@ -26,7 +26,7 @@ use Symfony\Component\HttpKernel\KernelEvents;
*/
class SurrogateListener implements EventSubscriberInterface
{
private $surrogate;
private ?SurrogateInterface $surrogate;
public function __construct(SurrogateInterface $surrogate = null)
{

View File

@@ -1,46 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\EventListener;
use Psr\Container\ContainerInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
trigger_deprecation('symfony/http-kernel', '5.4', '"%s" is deprecated, use "%s" instead.', TestSessionListener::class, SessionListener::class);
/**
* Sets the session in the request.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final
*
* @deprecated since Symfony 5.4, use SessionListener instead
*/
class TestSessionListener extends AbstractTestSessionListener
{
private $container;
public function __construct(ContainerInterface $container, array $sessionOptions = [])
{
$this->container = $container;
parent::__construct($sessionOptions);
}
protected function getSession(): ?SessionInterface
{
if ($this->container->has('session')) {
return $this->container->get('session');
}
return null;
}
}

View File

@@ -41,9 +41,6 @@ class ValidateRequestListener implements EventSubscriberInterface
$request->getHost();
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array
{
return [

View File

@@ -17,19 +17,8 @@ namespace Symfony\Component\HttpKernel\Exception;
*/
class AccessDeniedHttpException extends HttpException
{
/**
* @param string|null $message The internal exception message
* @param \Throwable|null $previous The previous exception
* @param int $code The internal exception code
*/
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
parent::__construct(403, $message, $previous, $headers, $code);
}
}

View File

@@ -16,19 +16,8 @@ namespace Symfony\Component\HttpKernel\Exception;
*/
class BadRequestHttpException extends HttpException
{
/**
* @param string|null $message The internal exception message
* @param \Throwable|null $previous The previous exception
* @param int $code The internal exception code
*/
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
parent::__construct(400, $message, $previous, $headers, $code);
}
}

View File

@@ -16,19 +16,8 @@ namespace Symfony\Component\HttpKernel\Exception;
*/
class ConflictHttpException extends HttpException
{
/**
* @param string|null $message The internal exception message
* @param \Throwable|null $previous The previous exception
* @param int $code The internal exception code
*/
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
parent::__construct(409, $message, $previous, $headers, $code);
}
}

View File

@@ -27,7 +27,6 @@ class ControllerDoesNotReturnResponseException extends \LogicException
$this->file = $controllerDefinition['file'];
$this->line = $controllerDefinition['line'];
$r = new \ReflectionProperty(\Exception::class, 'trace');
$r->setAccessible(true);
$r->setValue($this, array_merge([
[
'line' => $line,
@@ -50,7 +49,7 @@ class ControllerDoesNotReturnResponseException extends \LogicException
'file' => $r->getFileName(),
'line' => $r->getEndLine(),
];
} catch (\ReflectionException $e) {
} catch (\ReflectionException) {
return null;
}
}
@@ -69,7 +68,7 @@ class ControllerDoesNotReturnResponseException extends \LogicException
try {
$line = $r->getMethod('__invoke')->getEndLine();
} catch (\ReflectionException $e) {
} catch (\ReflectionException) {
$line = $r->getEndLine();
}

View File

@@ -16,19 +16,8 @@ namespace Symfony\Component\HttpKernel\Exception;
*/
class GoneHttpException extends HttpException
{
/**
* @param string|null $message The internal exception message
* @param \Throwable|null $previous The previous exception
* @param int $code The internal exception code
*/
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
parent::__construct(410, $message, $previous, $headers, $code);
}
}

View File

@@ -18,43 +18,27 @@ namespace Symfony\Component\HttpKernel\Exception;
*/
class HttpException extends \RuntimeException implements HttpExceptionInterface
{
private $statusCode;
private $headers;
private int $statusCode;
private array $headers;
public function __construct(int $statusCode, ?string $message = '', \Throwable $previous = null, array $headers = [], ?int $code = 0)
public function __construct(int $statusCode, string $message = '', \Throwable $previous = null, array $headers = [], int $code = 0)
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
if (null === $code) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $code to "%s()" is deprecated, pass 0 instead.', __METHOD__);
$code = 0;
}
$this->statusCode = $statusCode;
$this->headers = $headers;
parent::__construct($message, $code, $previous);
}
public function getStatusCode()
public function getStatusCode(): int
{
return $this->statusCode;
}
public function getHeaders()
public function getHeaders(): array
{
return $this->headers;
}
/**
* Set response headers.
*
* @param array $headers Response headers
*/
public function setHeaders(array $headers)
{
$this->headers = $headers;

View File

@@ -20,15 +20,11 @@ interface HttpExceptionInterface extends \Throwable
{
/**
* Returns the status code.
*
* @return int
*/
public function getStatusCode();
public function getStatusCode(): int;
/**
* Returns response headers.
*
* @return array
*/
public function getHeaders();
public function getHeaders(): array;
}

View File

@@ -16,19 +16,8 @@ namespace Symfony\Component\HttpKernel\Exception;
*/
class LengthRequiredHttpException extends HttpException
{
/**
* @param string|null $message The internal exception message
* @param \Throwable|null $previous The previous exception
* @param int $code The internal exception code
*/
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
parent::__construct(411, $message, $previous, $headers, $code);
}
}

View File

@@ -0,0 +1,23 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Exception;
/**
* @author Peter Dietrich <xosofox@gmail.com>
*/
class LockedHttpException extends HttpException
{
public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
parent::__construct(423, $message, $previous, $headers, $code);
}
}

View File

@@ -17,24 +17,10 @@ namespace Symfony\Component\HttpKernel\Exception;
class MethodNotAllowedHttpException extends HttpException
{
/**
* @param string[] $allow An array of allowed methods
* @param string|null $message The internal exception message
* @param \Throwable|null $previous The previous exception
* @param int|null $code The internal exception code
* @param string[] $allow An array of allowed methods
*/
public function __construct(array $allow, ?string $message = '', \Throwable $previous = null, ?int $code = 0, array $headers = [])
public function __construct(array $allow, string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
if (null === $code) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $code to "%s()" is deprecated, pass 0 instead.', __METHOD__);
$code = 0;
}
$headers['Allow'] = strtoupper(implode(', ', $allow));
parent::__construct(405, $message, $previous, $headers, $code);

View File

@@ -16,19 +16,8 @@ namespace Symfony\Component\HttpKernel\Exception;
*/
class NotAcceptableHttpException extends HttpException
{
/**
* @param string|null $message The internal exception message
* @param \Throwable|null $previous The previous exception
* @param int $code The internal exception code
*/
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
parent::__construct(406, $message, $previous, $headers, $code);
}
}

View File

@@ -16,19 +16,8 @@ namespace Symfony\Component\HttpKernel\Exception;
*/
class NotFoundHttpException extends HttpException
{
/**
* @param string|null $message The internal exception message
* @param \Throwable|null $previous The previous exception
* @param int $code The internal exception code
*/
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
parent::__construct(404, $message, $previous, $headers, $code);
}
}

View File

@@ -16,19 +16,8 @@ namespace Symfony\Component\HttpKernel\Exception;
*/
class PreconditionFailedHttpException extends HttpException
{
/**
* @param string|null $message The internal exception message
* @param \Throwable|null $previous The previous exception
* @param int $code The internal exception code
*/
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
parent::__construct(412, $message, $previous, $headers, $code);
}
}

Some files were not shown because too many files have changed in this diff Show More