updated-packages

This commit is contained in:
RafficMohammed
2023-01-08 00:13:22 +05:30
parent 3ff7df7487
commit da241bacb6
12659 changed files with 563377 additions and 510538 deletions

View File

@@ -1,5 +0,0 @@
vendor/
composer.lock
phpunit.xml
Tests/Fixtures/cache/
Tests/Fixtures/logs/

View File

@@ -18,8 +18,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
/**
* An implementation of BundleInterface that adds a few conventions
* for DependencyInjection extensions and Console commands.
* An implementation of BundleInterface that adds a few conventions for DependencyInjection extensions.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
@@ -70,7 +69,7 @@ abstract class Bundle implements BundleInterface
if (null !== $extension) {
if (!$extension instanceof ExtensionInterface) {
throw new \LogicException(sprintf('Extension %s must implement Symfony\Component\DependencyInjection\Extension\ExtensionInterface.', \get_class($extension)));
throw new \LogicException(sprintf('Extension "%s" must implement Symfony\Component\DependencyInjection\Extension\ExtensionInterface.', \get_class($extension)));
}
// check naming convention
@@ -87,9 +86,7 @@ abstract class Bundle implements BundleInterface
}
}
if ($this->extension) {
return $this->extension;
}
return $this->extension ?: null;
}
/**
@@ -119,10 +116,8 @@ abstract class Bundle implements BundleInterface
/**
* Returns the bundle name (the class short name).
*
* @return string The Bundle name
*/
final public function getName()
final public function getName(): string
{
if (null === $this->name) {
$this->parseClassName();
@@ -154,9 +149,7 @@ abstract class Bundle implements BundleInterface
*/
protected function createContainerExtension()
{
if (class_exists($class = $this->getContainerExtensionClass())) {
return new $class();
}
return class_exists($class = $this->getContainerExtensionClass()) ? new $class() : null;
}
private function parseClassName()

View File

@@ -1,13 +1,61 @@
CHANGELOG
=========
4.4.0
-----
* The `DebugHandlersListener` class has been marked as `final`
* Added new Bundle directory convention consistent with standard skeletons
* Deprecated the second and third argument of `KernelInterface::locateResource`
* Deprecated the second and third argument of `FileLocator::__construct`
* Deprecated loading resources from `%kernel.root_dir%/Resources` and `%kernel.root_dir%` as
fallback directories. Resources like service definitions are usually loaded relative to the
current directory or with a glob pattern. The fallback directories have never been advocated
so you likely do not use those in any app based on the SF Standard or Flex edition.
* Marked all dispatched event classes as `@final`
* Added `ErrorController` to enable the preview and error rendering mechanism
* Getting the container from a non-booted kernel is deprecated.
* Marked the `AjaxDataCollector`, `ConfigDataCollector`, `EventDataCollector`,
`ExceptionDataCollector`, `LoggerDataCollector`, `MemoryDataCollector`,
`RequestDataCollector` and `TimeDataCollector` classes as `@final`.
* Marked the `RouterDataCollector::collect()` method as `@final`.
* The `DataCollectorInterface::collect()` and `Profiler::collect()` methods third parameter signature
will be `\Throwable $exception = null` instead of `\Exception $exception = null` in Symfony 5.0.
* Deprecated methods `ExceptionEvent::get/setException()`, use `get/setThrowable()` instead
* Deprecated class `ExceptionListener`, use `ErrorListener` instead
4.3.0
-----
* renamed `Client` to `HttpKernelBrowser`
* `KernelInterface` doesn't extend `Serializable` anymore
* deprecated the `Kernel::serialize()` and `unserialize()` methods
* increased the priority of `Symfony\Component\HttpKernel\EventListener\AddRequestFormatsListener`
* made `Symfony\Component\HttpKernel\EventListener\LocaleListener` set the default locale early
* deprecated `TranslatorListener` in favor of `LocaleAwareListener`
* added the registration of all `LocaleAwareInterface` implementations into the `LocaleAwareListener`
* made `FileLinkFormatter` final and not implement `Serializable` anymore
* the base `DataCollector` doesn't implement `Serializable` anymore, you should
store all the serialized state in the data property instead
* `DumpDataCollector` has been marked as `final`
* added an event listener to prevent search engines from indexing applications in debug mode.
* renamed `FilterControllerArgumentsEvent` to `ControllerArgumentsEvent`
* renamed `FilterControllerEvent` to `ControllerEvent`
* renamed `FilterResponseEvent` to `ResponseEvent`
* renamed `GetResponseEvent` to `RequestEvent`
* renamed `GetResponseForControllerResultEvent` to `ViewEvent`
* renamed `GetResponseForExceptionEvent` to `ExceptionEvent`
* renamed `PostResponseEvent` to `TerminateEvent`
* added `HttpClientKernel` for handling requests with an `HttpClientInterface` instance
* added `trace_header` and `trace_level` configuration options to `HttpCache`
4.2.0
-----
* deprecated `KernelInterface::getRootDir()` and the `kernel.root_dir` parameter
* deprecated `KernelInterface::getName()` and the `kernel.name` parameter
* deprecated the first and second constructor argument of `ConfigDataCollector`
* deprecated `ConfigDataCollector::getApplicationName()`
* deprecated the first and second constructor argument of `ConfigDataCollector`
* deprecated `ConfigDataCollector::getApplicationName()`
* deprecated `ConfigDataCollector::getApplicationVersion()`
4.1.0

View File

@@ -22,7 +22,7 @@ class ChainCacheClearer implements CacheClearerInterface
{
private $clearers;
public function __construct(iterable $clearers = array())
public function __construct(iterable $clearers = [])
{
$this->clearers = $clearers;
}

View File

@@ -16,9 +16,9 @@ namespace Symfony\Component\HttpKernel\CacheClearer;
*/
class Psr6CacheClearer implements CacheClearerInterface
{
private $pools = array();
private $pools = [];
public function __construct(array $pools = array())
public function __construct(array $pools = [])
{
$this->pools = $pools;
}
@@ -31,7 +31,7 @@ class Psr6CacheClearer implements CacheClearerInterface
public function getPool($name)
{
if (!$this->hasPool($name)) {
throw new \InvalidArgumentException(sprintf('Cache pool not found: %s.', $name));
throw new \InvalidArgumentException(sprintf('Cache pool not found: "%s".', $name));
}
return $this->pools[$name];
@@ -40,7 +40,7 @@ class Psr6CacheClearer implements CacheClearerInterface
public function clearPool($name)
{
if (!isset($this->pools[$name])) {
throw new \InvalidArgumentException(sprintf('Cache pool not found: %s.', $name));
throw new \InvalidArgumentException(sprintf('Cache pool not found: "%s".', $name));
}
return $this->pools[$name]->clear();

View File

@@ -26,7 +26,7 @@ class CacheWarmerAggregate implements CacheWarmerInterface
private $optionalsEnabled = false;
private $onlyOptionalsEnabled = false;
public function __construct(iterable $warmers = array(), bool $debug = false, string $deprecationLogsFilepath = null)
public function __construct(iterable $warmers = [], bool $debug = false, string $deprecationLogsFilepath = null)
{
$this->warmers = $warmers;
$this->debug = $debug;
@@ -50,21 +50,20 @@ class CacheWarmerAggregate implements CacheWarmerInterface
*/
public function warmUp($cacheDir)
{
if ($this->debug) {
$collectedLogs = array();
$previousHandler = \defined('PHPUNIT_COMPOSER_INSTALL');
$previousHandler = $previousHandler ?: set_error_handler(function ($type, $message, $file, $line) use (&$collectedLogs, &$previousHandler) {
if (E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) {
if ($collectDeprecations = $this->debug && !\defined('PHPUNIT_COMPOSER_INSTALL')) {
$collectedLogs = [];
$previousHandler = set_error_handler(function ($type, $message, $file, $line) use (&$collectedLogs, &$previousHandler) {
if (\E_USER_DEPRECATED !== $type && \E_DEPRECATED !== $type) {
return $previousHandler ? $previousHandler($type, $message, $file, $line) : false;
}
if (isset($collectedLogs[$message])) {
++$collectedLogs[$message]['count'];
return;
return null;
}
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
$backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 3);
// Clean the trace by removing first frames added by the error handler itself.
for ($i = 0; isset($backtrace[$i]); ++$i) {
if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) {
@@ -73,14 +72,16 @@ class CacheWarmerAggregate implements CacheWarmerInterface
}
}
$collectedLogs[$message] = array(
$collectedLogs[$message] = [
'type' => $type,
'message' => $message,
'file' => $file,
'line' => $line,
'trace' => $backtrace,
'count' => 1,
);
];
return null;
});
}
@@ -96,12 +97,14 @@ class CacheWarmerAggregate implements CacheWarmerInterface
$warmer->warmUp($cacheDir);
}
} finally {
if ($this->debug && true !== $previousHandler) {
if ($collectDeprecations) {
restore_error_handler();
if (file_exists($this->deprecationLogsFilepath)) {
$previousLogs = unserialize(file_get_contents($this->deprecationLogsFilepath));
$collectedLogs = array_merge($previousLogs, $collectedLogs);
if (\is_array($previousLogs)) {
$collectedLogs = array_merge($previousLogs, $collectedLogs);
}
}
file_put_contents($this->deprecationLogsFilepath, serialize(array_values($collectedLogs)));
@@ -114,7 +117,7 @@ class CacheWarmerAggregate implements CacheWarmerInterface
*
* @return bool always false
*/
public function isOptional()
public function isOptional(): bool
{
return false;
}

View File

@@ -11,7 +11,7 @@
namespace Symfony\Component\HttpKernel;
use Symfony\Component\BrowserKit\Client as BaseClient;
use Symfony\Component\BrowserKit\AbstractBrowser;
use Symfony\Component\BrowserKit\CookieJar;
use Symfony\Component\BrowserKit\History;
use Symfony\Component\BrowserKit\Request as DomRequest;
@@ -21,25 +21,22 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* Client simulates a browser and makes requests to a Kernel object.
*
* @author Fabien Potencier <fabien@symfony.com>
* Client simulates a browser and makes requests to an HttpKernel instance.
*
* @method Request getRequest() A Request instance
* @method Response getResponse() A Response instance
*
* @deprecated since Symfony 4.3, use HttpKernelBrowser instead.
*/
class Client extends BaseClient
class Client extends AbstractBrowser
{
protected $kernel;
private $catchExceptions = true;
/**
* @param HttpKernelInterface $kernel An HttpKernel instance
* @param array $server The server parameters (equivalent of $_SERVER)
* @param History $history A History instance to store the browser history
* @param CookieJar $cookieJar A CookieJar instance to store the cookies
* @param array $server The server parameters (equivalent of $_SERVER)
*/
public function __construct(HttpKernelInterface $kernel, array $server = array(), History $history = null, CookieJar $cookieJar = null)
public function __construct(HttpKernelInterface $kernel, array $server = [], History $history = null, CookieJar $cookieJar = null)
{
// These class properties must be set before calling the parent constructor, as it may depend on it.
$this->kernel = $kernel;
@@ -88,9 +85,9 @@ class Client extends BaseClient
$requires = '';
foreach (get_declared_classes() as $class) {
if (0 === strpos($class, 'ComposerAutoloaderInit')) {
if (str_starts_with($class, 'ComposerAutoloaderInit')) {
$r = new \ReflectionClass($class);
$file = \dirname(\dirname($r->getFileName())).'/autoload.php';
$file = \dirname($r->getFileName(), 2).'/autoload.php';
if (file_exists($file)) {
$requires .= 'require_once '.var_export($file, true).";\n";
}
@@ -159,7 +156,7 @@ EOF;
*/
protected function filterFiles(array $files)
{
$filtered = array();
$filtered = [];
foreach ($files as $key => $value) {
if (\is_array($value)) {
$filtered[$key] = $this->filterFiles($value);
@@ -169,7 +166,7 @@ EOF;
'',
$value->getClientOriginalName(),
$value->getClientMimeType(),
UPLOAD_ERR_INI_SIZE,
\UPLOAD_ERR_INI_SIZE,
true
);
} else {

View File

@@ -22,19 +22,28 @@ use Symfony\Component\HttpKernel\KernelInterface;
class FileLocator extends BaseFileLocator
{
private $kernel;
private $path;
/**
* @param KernelInterface $kernel A KernelInterface instance
* @param string|null $path The path the global resource directory
* @param array $paths An array of paths where to look for resources
* @deprecated since Symfony 4.4
*/
public function __construct(KernelInterface $kernel, string $path = null, array $paths = array())
private $path;
public function __construct(KernelInterface $kernel/* , string $path = null, array $paths = [], bool $triggerDeprecation = true */)
{
$this->kernel = $kernel;
if (null !== $path) {
$this->path = $path;
$paths[] = $path;
if (2 <= \func_num_args()) {
$this->path = func_get_arg(1);
$paths = 3 <= \func_num_args() ? func_get_arg(2) : [];
if (null !== $this->path) {
$paths[] = $this->path;
}
if (4 !== \func_num_args() || func_get_arg(3)) {
@trigger_error(sprintf('Passing more than one argument to %s is deprecated since Symfony 4.4 and will be removed in 5.0.', __METHOD__), \E_USER_DEPRECATED);
}
} else {
$paths = [];
}
parent::__construct($paths);
@@ -46,9 +55,36 @@ class FileLocator extends BaseFileLocator
public function locate($file, $currentPath = null, $first = true)
{
if (isset($file[0]) && '@' === $file[0]) {
return $this->kernel->locateResource($file, $this->path, $first);
return $this->kernel->locateResource($file, $this->path, $first, false);
}
return parent::locate($file, $currentPath, $first);
$locations = parent::locate($file, $currentPath, $first);
if (isset($file[0]) && !(
'/' === $file[0] || '\\' === $file[0]
|| (\strlen($file) > 3 && ctype_alpha($file[0]) && ':' === $file[1] && ('\\' === $file[2] || '/' === $file[2]))
|| null !== parse_url($file, \PHP_URL_SCHEME)
)) {
$deprecation = false;
// no need to trigger deprecations when the loaded file is given as absolute path
foreach ($this->paths as $deprecatedPath) {
foreach ((array) $locations as $location) {
if (null !== $currentPath && str_starts_with($location, $currentPath)) {
return $locations;
}
if (str_starts_with($location, $deprecatedPath) && (null === $currentPath || !str_contains($location, $currentPath))) {
$deprecation = sprintf('Loading the file "%s" from the global resource directory "%s" is deprecated since Symfony 4.4 and will be removed in 5.0.', $file, $deprecatedPath);
}
}
}
if ($deprecation) {
@trigger_error($deprecation, \E_USER_DEPRECATED);
}
}
return $locations;
}
}

View File

@@ -34,18 +34,18 @@ final class ArgumentResolver implements ArgumentResolverInterface
*/
private $argumentValueResolvers;
public function __construct(ArgumentMetadataFactoryInterface $argumentMetadataFactory = null, iterable $argumentValueResolvers = array())
public function __construct(ArgumentMetadataFactoryInterface $argumentMetadataFactory = null, iterable $argumentValueResolvers = [])
{
$this->argumentMetadataFactory = $argumentMetadataFactory ?: new ArgumentMetadataFactory();
$this->argumentMetadataFactory = $argumentMetadataFactory ?? new ArgumentMetadataFactory();
$this->argumentValueResolvers = $argumentValueResolvers ?: self::getDefaultArgumentValueResolvers();
}
/**
* {@inheritdoc}
*/
public function getArguments(Request $request, $controller)
public function getArguments(Request $request, $controller): array
{
$arguments = array();
$arguments = [];
foreach ($this->argumentMetadataFactory->createArgumentMetadata($controller) as $metadata) {
foreach ($this->argumentValueResolvers as $resolver) {
@@ -55,12 +55,14 @@ final class ArgumentResolver implements ArgumentResolverInterface
$resolved = $resolver->resolve($request, $metadata);
if (!$resolved instanceof \Generator) {
throw new \InvalidArgumentException(sprintf('%s::resolve() must yield at least one value.', \get_class($resolver)));
$atLeastOne = false;
foreach ($resolved as $append) {
$atLeastOne = true;
$arguments[] = $append;
}
foreach ($resolved as $append) {
$arguments[] = $append;
if (!$atLeastOne) {
throw new \InvalidArgumentException(sprintf('"%s::resolve()" must yield at least one value.', \get_class($resolver)));
}
// continue to the next controller argument
@@ -83,12 +85,12 @@ final class ArgumentResolver implements ArgumentResolverInterface
public static function getDefaultArgumentValueResolvers(): iterable
{
return array(
return [
new RequestAttributeValueResolver(),
new RequestValueResolver(),
new SessionValueResolver(),
new DefaultValueResolver(),
new VariadicValueResolver(),
);
];
}
}

View File

@@ -25,7 +25,7 @@ final class DefaultValueResolver implements ArgumentValueResolverInterface
/**
* {@inheritdoc}
*/
public function supports(Request $request, ArgumentMetadata $argument)
public function supports(Request $request, ArgumentMetadata $argument): bool
{
return $argument->hasDefaultValue() || (null !== $argument->getType() && $argument->isNullable() && !$argument->isVariadic());
}
@@ -33,7 +33,7 @@ final class DefaultValueResolver implements ArgumentValueResolverInterface
/**
* {@inheritdoc}
*/
public function resolve(Request $request, ArgumentMetadata $argument)
public function resolve(Request $request, ArgumentMetadata $argument): iterable
{
yield $argument->hasDefaultValue() ? $argument->getDefaultValue() : null;
}

View File

@@ -0,0 +1,82 @@
<?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 Psr\Container\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
/**
* Provides an intuitive error message when controller fails because it is not registered as a service.
*
* @author Simeon Kolev <simeon.kolev9@gmail.com>
*/
final class NotTaggedControllerValueResolver implements ArgumentValueResolverInterface
{
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/**
* {@inheritdoc}
*/
public function supports(Request $request, ArgumentMetadata $argument): bool
{
$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 false;
}
if ('\\' === $controller[0]) {
$controller = ltrim($controller, '\\');
}
if (!$this->container->has($controller) && false !== $i = strrpos($controller, ':')) {
$controller = substr($controller, 0, $i).strtolower(substr($controller, $i));
}
return false === $this->container->has($controller);
}
/**
* {@inheritdoc}
*/
public function resolve(Request $request, ArgumentMetadata $argument): iterable
{
if (\is_array($controller = $request->attributes->get('_controller'))) {
$controller = $controller[0].'::'.$controller[1];
}
if ('\\' === $controller[0]) {
$controller = ltrim($controller, '\\');
}
if (!$this->container->has($controller)) {
$controller = (false !== $i = strrpos($controller, ':'))
? substr($controller, 0, $i).strtolower(substr($controller, $i))
: $controller.'::__invoke';
}
$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);
throw new RuntimeException($message);
}
}

View File

@@ -25,7 +25,7 @@ final class RequestAttributeValueResolver implements ArgumentValueResolverInterf
/**
* {@inheritdoc}
*/
public function supports(Request $request, ArgumentMetadata $argument)
public function supports(Request $request, ArgumentMetadata $argument): bool
{
return !$argument->isVariadic() && $request->attributes->has($argument->getName());
}
@@ -33,7 +33,7 @@ final class RequestAttributeValueResolver implements ArgumentValueResolverInterf
/**
* {@inheritdoc}
*/
public function resolve(Request $request, ArgumentMetadata $argument)
public function resolve(Request $request, ArgumentMetadata $argument): iterable
{
yield $request->attributes->get($argument->getName());
}

View File

@@ -25,7 +25,7 @@ final class RequestValueResolver implements ArgumentValueResolverInterface
/**
* {@inheritdoc}
*/
public function supports(Request $request, ArgumentMetadata $argument)
public function supports(Request $request, ArgumentMetadata $argument): bool
{
return Request::class === $argument->getType() || is_subclass_of($argument->getType(), Request::class);
}
@@ -33,7 +33,7 @@ final class RequestValueResolver implements ArgumentValueResolverInterface
/**
* {@inheritdoc}
*/
public function resolve(Request $request, ArgumentMetadata $argument)
public function resolve(Request $request, ArgumentMetadata $argument): iterable
{
yield $request;
}

View File

@@ -34,7 +34,7 @@ final class ServiceValueResolver implements ArgumentValueResolverInterface
/**
* {@inheritdoc}
*/
public function supports(Request $request, ArgumentMetadata $argument)
public function supports(Request $request, ArgumentMetadata $argument): bool
{
$controller = $request->attributes->get('_controller');
@@ -58,7 +58,7 @@ final class ServiceValueResolver implements ArgumentValueResolverInterface
/**
* {@inheritdoc}
*/
public function resolve(Request $request, ArgumentMetadata $argument)
public function resolve(Request $request, ArgumentMetadata $argument): iterable
{
if (\is_array($controller = $request->attributes->get('_controller'))) {
$controller = $controller[0].'::'.$controller[1];

View File

@@ -26,7 +26,7 @@ final class SessionValueResolver implements ArgumentValueResolverInterface
/**
* {@inheritdoc}
*/
public function supports(Request $request, ArgumentMetadata $argument)
public function supports(Request $request, ArgumentMetadata $argument): bool
{
if (!$request->hasSession()) {
return false;
@@ -43,7 +43,7 @@ final class SessionValueResolver implements ArgumentValueResolverInterface
/**
* {@inheritdoc}
*/
public function resolve(Request $request, ArgumentMetadata $argument)
public function resolve(Request $request, ArgumentMetadata $argument): iterable
{
yield $request->getSession();
}

View File

@@ -25,7 +25,7 @@ final class VariadicValueResolver implements ArgumentValueResolverInterface
/**
* {@inheritdoc}
*/
public function supports(Request $request, ArgumentMetadata $argument)
public function supports(Request $request, ArgumentMetadata $argument): bool
{
return $argument->isVariadic() && $request->attributes->has($argument->getName());
}
@@ -33,7 +33,7 @@ final class VariadicValueResolver implements ArgumentValueResolverInterface
/**
* {@inheritdoc}
*/
public function resolve(Request $request, ArgumentMetadata $argument)
public function resolve(Request $request, ArgumentMetadata $argument): iterable
{
$values = $request->attributes->get($argument->getName());
@@ -41,8 +41,6 @@ final class VariadicValueResolver implements ArgumentValueResolverInterface
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(), \gettype($values)));
}
foreach ($values as $value) {
yield $value;
}
yield from $values;
}
}

View File

@@ -24,7 +24,6 @@ interface ArgumentResolverInterface
/**
* Returns the arguments to pass to the controller.
*
* @param Request $request
* @param callable $controller
*
* @return array An array of arguments to pass to the controller

View File

@@ -24,9 +24,6 @@ interface ArgumentValueResolverInterface
/**
* Whether this resolver can resolve the value for the given ArgumentMetadata.
*
* @param Request $request
* @param ArgumentMetadata $argument
*
* @return bool
*/
public function supports(Request $request, ArgumentMetadata $argument);
@@ -34,10 +31,7 @@ interface ArgumentValueResolverInterface
/**
* Returns the possible value(s).
*
* @param Request $request
* @param ArgumentMetadata $argument
*
* @return \Generator
* @return iterable
*/
public function resolve(Request $request, ArgumentMetadata $argument);
}

View File

@@ -47,6 +47,8 @@ class ContainerControllerResolver extends ControllerResolver
*/
protected function instantiateController($class)
{
$class = ltrim($class, '\\');
if ($this->container->has($class)) {
return $this->container->get($class);
}
@@ -59,10 +61,10 @@ class ContainerControllerResolver extends ControllerResolver
$this->throwExceptionIfControllerWasRemoved($class, $e);
if ($e instanceof \ArgumentCountError) {
throw new \InvalidArgumentException(sprintf('Controller "%s" has required constructor arguments and does not exist in the container. Did you forget to define such a service?', $class), 0, $e);
throw new \InvalidArgumentException(sprintf('Controller "%s" has required constructor arguments and does not exist in the container. Did you forget to define the controller as a service?', $class), 0, $e);
}
throw new \InvalidArgumentException(sprintf('Controller "%s" does neither exist as service nor as class', $class), 0, $e);
throw new \InvalidArgumentException(sprintf('Controller "%s" does neither exist as service nor as class.', $class), 0, $e);
}
private function throwExceptionIfControllerWasRemoved(string $controller, \Throwable $previous)

View File

@@ -27,15 +27,15 @@ use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface;
class ControllerReference
{
public $controller;
public $attributes = array();
public $query = array();
public $attributes = [];
public $query = [];
/**
* @param string $controller The controller name
* @param array $attributes An array of parameters to add to the Request attributes
* @param array $query An array of parameters to add to the Request query string
*/
public function __construct(string $controller, array $attributes = array(), array $query = array())
public function __construct(string $controller, array $attributes = [], array $query = [])
{
$this->controller = $controller;
$this->attributes = $attributes;

View File

@@ -47,7 +47,7 @@ class ControllerResolver implements ControllerResolverInterface
if (isset($controller[0]) && \is_string($controller[0]) && isset($controller[1])) {
try {
$controller[0] = $this->instantiateController($controller[0]);
} catch (\Error | \LogicException $e) {
} 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
@@ -64,7 +64,7 @@ class ControllerResolver implements ControllerResolverInterface
}
if (!\is_callable($controller)) {
throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable. %s', $request->getPathInfo(), $this->getControllerError($controller)));
throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$this->getControllerError($controller));
}
return $controller;
@@ -72,7 +72,7 @@ class ControllerResolver implements ControllerResolverInterface
if (\is_object($controller)) {
if (!\is_callable($controller)) {
throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable. %s', $request->getPathInfo(), $this->getControllerError($controller)));
throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: '.$this->getControllerError($controller), $request->getPathInfo()));
}
return $controller;
@@ -82,10 +82,14 @@ class ControllerResolver implements ControllerResolverInterface
return $controller;
}
$callable = $this->createController($controller);
try {
$callable = $this->createController($controller);
} catch (\InvalidArgumentException $e) {
throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$e->getMessage(), 0, $e);
}
if (!\is_callable($callable)) {
throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable. %s', $request->getPathInfo(), $this->getControllerError($callable)));
throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: '.$this->getControllerError($callable), $request->getPathInfo()));
}
return $callable;
@@ -97,18 +101,26 @@ class ControllerResolver implements ControllerResolverInterface
* @param string $controller A Controller string
*
* @return callable A PHP callable
*
* @throws \InvalidArgumentException When the controller cannot be created
*/
protected function createController($controller)
{
if (false === strpos($controller, '::')) {
return $this->instantiateController($controller);
if (!str_contains($controller, '::')) {
$controller = $this->instantiateController($controller);
if (!\is_callable($controller)) {
throw new \InvalidArgumentException($this->getControllerError($controller));
}
return $controller;
}
list($class, $method) = explode('::', $controller, 2);
[$class, $method] = explode('::', $controller, 2);
try {
return array($this->instantiateController($class), $method);
} catch (\Error | \LogicException $e) {
$controller = [$this->instantiateController($class), $method];
} catch (\Error|\LogicException $e) {
try {
if ((new \ReflectionMethod($class, $method))->isStatic()) {
return $class.'::'.$method;
@@ -119,6 +131,12 @@ class ControllerResolver implements ControllerResolverInterface
throw $e;
}
if (!\is_callable($controller)) {
throw new \InvalidArgumentException($this->getControllerError($controller));
}
return $controller;
}
/**
@@ -133,10 +151,10 @@ class ControllerResolver implements ControllerResolverInterface
return new $class();
}
private function getControllerError($callable)
private function getControllerError($callable): string
{
if (\is_string($callable)) {
if (false !== strpos($callable, '::')) {
if (str_contains($callable, '::')) {
$callable = explode('::', $callable, 2);
} else {
return sprintf('Function "%s" does not exist.', $callable);
@@ -155,10 +173,10 @@ class ControllerResolver implements ControllerResolverInterface
}
if (!isset($callable[0]) || !isset($callable[1]) || 2 !== \count($callable)) {
return 'Invalid array callable, expected array(controller, method).';
return 'Invalid array callable, expected [controller, method].';
}
list($controller, $method) = $callable;
[$controller, $method] = $callable;
if (\is_string($controller) && !class_exists($controller)) {
return sprintf('Class "%s" does not exist.', $controller);
@@ -172,12 +190,12 @@ class ControllerResolver implements ControllerResolverInterface
$collection = $this->getClassMethodsWithoutMagicMethods($controller);
$alternatives = array();
$alternatives = [];
foreach ($collection as $item) {
$lev = levenshtein($method, $item);
if ($lev <= \strlen($method) / 3 || false !== strpos($item, $method)) {
if ($lev <= \strlen($method) / 3 || str_contains($item, $method)) {
$alternatives[] = $item;
}
}
@@ -195,7 +213,7 @@ class ControllerResolver implements ControllerResolverInterface
return $message;
}
private function getClassMethodsWithoutMagicMethods($classOrObject)
private function getClassMethodsWithoutMagicMethods($classOrObject): array
{
$methods = get_class_methods($classOrObject);

View File

@@ -29,7 +29,7 @@ interface ControllerResolverInterface
* As several resolvers can exist for a single application, a resolver must
* return false when it is not able to determine the controller.
*
* The resolver must only throw an exception when it should be able to load
* The resolver must only throw an exception when it should be able to load a
* controller but cannot because of some errors made by the developer.
*
* @return callable|false A PHP callable representing the Controller,

View File

@@ -0,0 +1,62 @@
<?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\ErrorHandler\ErrorRenderer\ErrorRendererInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Renders error or exception pages from a given FlattenException.
*
* @author Yonel Ceruto <yonelceruto@gmail.com>
* @author Matthias Pigulla <mp@webfactory.de>
*/
class ErrorController
{
private $kernel;
private $controller;
private $errorRenderer;
public function __construct(HttpKernelInterface $kernel, $controller, ErrorRendererInterface $errorRenderer)
{
$this->kernel = $kernel;
$this->controller = $controller;
$this->errorRenderer = $errorRenderer;
}
public function __invoke(\Throwable $exception): Response
{
$exception = $this->errorRenderer->render($exception);
return new Response($exception->getAsString(), $exception->getStatusCode(), $exception->getHeaders());
}
public function preview(Request $request, int $code): Response
{
/*
* This Request mimics the parameters set by
* \Symfony\Component\HttpKernel\EventListener\ErrorListener::duplicateRequest, with
* the additional "showException" flag.
*/
$subRequest = $request->duplicate(null, null, [
'_controller' => $this->controller,
'exception' => new HttpException($code, 'This is a sample exception.'),
'logger' => null,
'showException' => false,
]);
return $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
}
}

View File

@@ -50,7 +50,7 @@ class ArgumentMetadata
*
* The type is the PHP class in 5.5+ and additionally the basic type in PHP 7.0+.
*
* @return string
* @return string|null
*/
public function getType()
{
@@ -99,7 +99,7 @@ class ArgumentMetadata
public function getDefaultValue()
{
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__));
throw new \LogicException(sprintf('Argument $%s does not have a default value. Use "%s::hasDefaultValue()" to avoid this exception.', $this->name, __CLASS__));
}
return $this->defaultValue;

View File

@@ -21,20 +21,25 @@ final class ArgumentMetadataFactory implements ArgumentMetadataFactoryInterface
/**
* {@inheritdoc}
*/
public function createArgumentMetadata($controller)
public function createArgumentMetadata($controller): array
{
$arguments = array();
$arguments = [];
if (\is_array($controller)) {
$reflection = new \ReflectionMethod($controller[0], $controller[1]);
$class = $reflection->class;
} elseif (\is_object($controller) && !$controller instanceof \Closure) {
$reflection = (new \ReflectionObject($controller))->getMethod('__invoke');
$reflection = new \ReflectionMethod($controller, '__invoke');
$class = $reflection->class;
} else {
$reflection = new \ReflectionFunction($controller);
if ($class = str_contains($reflection->name, '{closure}') ? null : $reflection->getClosureScopeClass()) {
$class = $class->name;
}
}
foreach ($reflection->getParameters() as $param) {
$arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $reflection), $param->isVariadic(), $param->isDefaultValueAvailable(), $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, $param->allowsNull());
$arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $class), $param->isVariadic(), $param->isDefaultValueAvailable(), $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, $param->allowsNull());
}
return $arguments;
@@ -42,30 +47,23 @@ final class ArgumentMetadataFactory implements ArgumentMetadataFactoryInterface
/**
* Returns an associated type to the given parameter if available.
*
* @param \ReflectionParameter $parameter
*
* @return string|null
*/
private function getType(\ReflectionParameter $parameter, \ReflectionFunctionAbstract $function)
private function getType(\ReflectionParameter $parameter, ?string $class): ?string
{
if (!$type = $parameter->getType()) {
return;
return null;
}
$name = $type->getName();
$lcName = strtolower($name);
$name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type;
if ('self' !== $lcName && 'parent' !== $lcName) {
return $name;
}
if (!$function instanceof \ReflectionMethod) {
return;
}
if ('self' === $lcName) {
return $function->getDeclaringClass()->name;
}
if ($parent = $function->getDeclaringClass()->getParentClass()) {
return $parent->name;
if (null !== $class) {
switch (strtolower($name)) {
case 'self':
return $class;
case 'parent':
return get_parent_class($class) ?: null;
}
}
return $name;
}
}

View File

@@ -19,7 +19,7 @@ namespace Symfony\Component\HttpKernel\ControllerMetadata;
interface ArgumentMetadataFactoryInterface
{
/**
* @param mixed $controller The controller to resolve the arguments for
* @param string|object|array $controller The controller to resolve the arguments for
*
* @return ArgumentMetadata[]
*/

View File

@@ -18,10 +18,17 @@ use Symfony\Component\HttpFoundation\Response;
* AjaxDataCollector.
*
* @author Bart van den Burg <bart@burgov.nl>
*
* @final since Symfony 4.4
*/
class AjaxDataCollector extends DataCollector
{
public function collect(Request $request, Response $response, \Exception $exception = null)
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
{
// all collecting is done client side
}

View File

@@ -15,10 +15,12 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\VarDumper\Caster\LinkStub;
use Symfony\Component\VarDumper\Caster\ClassStub;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.4
*/
class ConfigDataCollector extends DataCollector implements LateDataCollectorInterface
{
@@ -28,20 +30,18 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
private $kernel;
private $name;
private $version;
private $hasVarDumper;
public function __construct(string $name = null, string $version = null)
{
if (1 <= \func_num_args()) {
@trigger_error(sprintf('The "$name" argument in method "%s()" is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED);
@trigger_error(sprintf('The "$name" argument in method "%s()" is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED);
}
if (2 <= \func_num_args()) {
@trigger_error(sprintf('The "$version" argument in method "%s()" is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED);
@trigger_error(sprintf('The "$version" argument in method "%s()" is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED);
}
$this->name = $name;
$this->version = $version;
$this->hasVarDumper = class_exists(LinkStub::class);
}
/**
@@ -54,39 +54,41 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response, \Exception $exception = null)
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
{
$this->data = array(
$eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE);
$eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE);
$this->data = [
'app_name' => $this->name,
'app_version' => $this->version,
'token' => $response->headers->get('X-Debug-Token'),
'symfony_version' => Kernel::VERSION,
'symfony_state' => 'unknown',
'symfony_minor_version' => sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION),
'symfony_lts' => 4 === Kernel::MINOR_VERSION,
'symfony_state' => $this->determineSymfonyState(),
'symfony_eom' => $eom->format('F Y'),
'symfony_eol' => $eol->format('F Y'),
'env' => isset($this->kernel) ? $this->kernel->getEnvironment() : 'n/a',
'debug' => isset($this->kernel) ? $this->kernel->isDebug() : 'n/a',
'php_version' => PHP_VERSION,
'php_architecture' => PHP_INT_SIZE * 8,
'php_intl_locale' => class_exists('Locale', false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a',
'php_version' => \PHP_VERSION,
'php_architecture' => \PHP_INT_SIZE * 8,
'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),
'bundles' => array(),
'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),
'bundles' => [],
'sapi_name' => \PHP_SAPI,
);
];
if (isset($this->kernel)) {
foreach ($this->kernel->getBundles() as $name => $bundle) {
$this->data['bundles'][$name] = $this->hasVarDumper ? new LinkStub($bundle->getPath()) : $bundle->getPath();
$this->data['bundles'][$name] = new ClassStub(\get_class($bundle));
}
$this->data['symfony_state'] = $this->determineSymfonyState();
$this->data['symfony_minor_version'] = sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION);
$eom = \DateTime::createFromFormat('m/Y', Kernel::END_OF_MAINTENANCE);
$eol = \DateTime::createFromFormat('m/Y', Kernel::END_OF_LIFE);
$this->data['symfony_eom'] = $eom->format('F Y');
$this->data['symfony_eol'] = $eol->format('F Y');
}
if (preg_match('~^(\d+(?:\.\d+)*)(.+)?$~', $this->data['php_version'], $matches) && isset($matches[2])) {
@@ -100,7 +102,7 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
*/
public function reset()
{
$this->data = array();
$this->data = [];
}
public function lateCollect()
@@ -113,7 +115,7 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
*/
public function getApplicationName()
{
@trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED);
@trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED);
return $this->data['app_name'];
}
@@ -123,7 +125,7 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
*/
public function getApplicationVersion()
{
@trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED);
@trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED);
return $this->data['app_version'];
}
@@ -131,7 +133,7 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
/**
* Gets the token.
*
* @return string The token
* @return string|null The token
*/
public function getToken()
{
@@ -170,7 +172,15 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
}
/**
* Returns the human redable date when this Symfony version ends its
* Returns if the current Symfony version is a Long-Term Support one.
*/
public function isSymfonyLts(): bool
{
return $this->data['symfony_lts'];
}
/**
* Returns the human readable date when this Symfony version ends its
* maintenance period.
*
* @return string
@@ -181,7 +191,7 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
}
/**
* Returns the human redable date when this Symfony version reaches its
* Returns the human readable date when this Symfony version reaches its
* "end of life" and won't receive bugs or security fixes.
*
* @return string
@@ -208,7 +218,7 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
*/
public function getPhpVersionExtra()
{
return isset($this->data['php_version_extra']) ? $this->data['php_version_extra'] : null;
return $this->data['php_version_extra'] ?? null;
}
/**
@@ -244,7 +254,7 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
*/
public function getAppName()
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED);
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED);
return 'n/a';
}
@@ -327,11 +337,11 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
*
* @return string One of: dev, stable, eom, eol
*/
private function determineSymfonyState()
private function determineSymfonyState(): string
{
$now = new \DateTime();
$eom = \DateTime::createFromFormat('m/Y', Kernel::END_OF_MAINTENANCE)->modify('last day of this month');
$eol = \DateTime::createFromFormat('m/Y', Kernel::END_OF_LIFE)->modify('last day of this month');
$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');
if ($now > $eol) {
$versionState = 'eol';

View File

@@ -12,6 +12,7 @@
namespace Symfony\Component\HttpKernel\DataCollector;
use Symfony\Component\VarDumper\Caster\CutStub;
use Symfony\Component\VarDumper\Caster\ReflectionCaster;
use Symfony\Component\VarDumper\Cloner\ClonerInterface;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Cloner\Stub;
@@ -25,23 +26,39 @@ use Symfony\Component\VarDumper\Cloner\VarCloner;
* @author Fabien Potencier <fabien@symfony.com>
* @author Bernhard Schussek <bschussek@symfony.com>
*/
abstract class DataCollector implements DataCollectorInterface, \Serializable
abstract class DataCollector implements DataCollectorInterface
{
protected $data = array();
/**
* @var array|Data
*/
protected $data = [];
/**
* @var ClonerInterface
*/
private $cloner;
/**
* @deprecated since Symfony 4.3, store all the serialized state in the data property instead
*/
public function serialize()
{
return serialize($this->data);
@trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.3, store all the serialized state in the data property instead.', __METHOD__), \E_USER_DEPRECATED);
$trace = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
$isCalledFromOverridingMethod = isset($trace[1]['function'], $trace[1]['object']) && 'serialize' === $trace[1]['function'] && $this === $trace[1]['object'];
return $isCalledFromOverridingMethod ? $this->data : serialize($this->data);
}
/**
* @deprecated since Symfony 4.3, store all the serialized state in the data property instead
*/
public function unserialize($data)
{
$this->data = unserialize($data);
@trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.3, store all the serialized state in the data property instead.', __METHOD__), \E_USER_DEPRECATED);
$this->data = \is_array($data) ? $data : unserialize($data);
}
/**
@@ -60,9 +77,6 @@ abstract class DataCollector implements DataCollectorInterface, \Serializable
return $var;
}
if (null === $this->cloner) {
if (!class_exists(CutStub::class)) {
throw new \LogicException(sprintf('The VarDumper component is needed for the %s() method. Install symfony/var-dumper version 3.4 or above.', __METHOD__));
}
$this->cloner = new VarCloner();
$this->cloner->setMaxItems(-1);
$this->cloner->addCasters($this->getCasters());
@@ -76,7 +90,7 @@ abstract class DataCollector implements DataCollectorInterface, \Serializable
*/
protected function getCasters()
{
return array(
$casters = [
'*' => function ($v, array $a, Stub $s, $isNested) {
if (!$v instanceof Stub) {
foreach ($a as $k => $v) {
@@ -88,6 +102,33 @@ abstract class DataCollector implements DataCollectorInterface, \Serializable
return $a;
},
);
] + ReflectionCaster::UNSET_CLOSURE_FILE_INFO;
return $casters;
}
/**
* @return array
*/
public function __sleep()
{
if (__CLASS__ !== $c = (new \ReflectionMethod($this, 'serialize'))->getDeclaringClass()->name) {
@trigger_error(sprintf('Implementing the "%s::serialize()" method is deprecated since Symfony 4.3, store all the serialized state in the "data" property instead.', $c), \E_USER_DEPRECATED);
$this->data = $this->serialize();
}
return ['data'];
}
public function __wakeup()
{
if (__CLASS__ !== $c = (new \ReflectionMethod($this, 'unserialize'))->getDeclaringClass()->name) {
if (\is_object($this->data)) {
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
}
@trigger_error(sprintf('Implementing the "%s::unserialize()" method is deprecated since Symfony 4.3, store all the serialized state in the "data" property instead.', $c), \E_USER_DEPRECATED);
$this->unserialize($this->data);
}
}
}

View File

@@ -24,8 +24,10 @@ interface DataCollectorInterface extends ResetInterface
{
/**
* Collects data for the given Request and Response.
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response, \Exception $exception = null);
public function collect(Request $request, Response $response/* , \Throwable $exception = null */);
/**
* Returns the name of the collector.

View File

@@ -14,6 +14,7 @@ namespace Symfony\Component\HttpKernel\DataCollector;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Cloner\VarCloner;
@@ -25,6 +26,8 @@ use Symfony\Component\VarDumper\Server\Connection;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.3
*/
class DumpDataCollector extends DataCollector implements DataDumperInterface
{
@@ -41,23 +44,25 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
private $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)
{
$fileLinkFormat = $fileLinkFormat ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
$this->stopwatch = $stopwatch;
$this->fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
$this->charset = $charset ?: ini_get('php.output_encoding') ?: ini_get('default_charset') ?: 'UTF-8';
$this->fileLinkFormat = $fileLinkFormat instanceof FileLinkFormatter && false === $fileLinkFormat->format('', 0) ? false : $fileLinkFormat;
$this->charset = $charset ?: \ini_get('php.output_encoding') ?: \ini_get('default_charset') ?: 'UTF-8';
$this->requestStack = $requestStack;
$this->dumper = $dumper;
// All clones share these properties by reference:
$this->rootRefs = array(
$this->rootRefs = [
&$this->data,
&$this->dataCount,
&$this->isCollected,
&$this->clonesCount,
);
];
$this->sourceContextProvider = $dumper instanceof Connection && isset($dumper->getContextProviders()['source']) ? $dumper->getContextProviders()['source'] : new SourceContextProvider($this->charset);
}
@@ -73,7 +78,7 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
$this->stopwatch->start('dump');
}
list('name' => $name, 'file' => $file, 'line' => $line, 'file_excerpt' => $fileExcerpt) = $this->sourceContextProvider->getContext();
['name' => $name, 'file' => $file, 'line' => $line, 'file_excerpt' => $fileExcerpt] = $this->sourceContextProvider->getContext();
if ($this->dumper instanceof Connection) {
if (!$this->dumper->write($data)) {
@@ -85,6 +90,9 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
$this->isCollected = false;
}
if (!$this->dataCount) {
$this->data = [];
}
$this->data[] = compact('data', 'name', 'file', 'line', 'fileExcerpt');
++$this->dataCount;
@@ -93,8 +101,17 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
}
}
public function collect(Request $request, Response $response, \Exception $exception = null)
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
{
if (!$this->dataCount) {
$this->data = [];
}
// Sub-requests and programmatic calls stay in the collected profile.
if ($this->dumper || ($this->requestStack && $this->requestStack->getMasterRequest() !== $request) || $request->isXmlHttpRequest() || $request->headers->has('Origin')) {
return;
@@ -104,15 +121,18 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
if (!$this->requestStack
|| !$response->headers->has('X-Debug-Token')
|| $response->isRedirection()
|| ($response->headers->has('Content-Type') && false === strpos($response->headers->get('Content-Type'), 'html'))
|| ($response->headers->has('Content-Type') && !str_contains($response->headers->get('Content-Type'), 'html'))
|| 'html' !== $request->getRequestFormat()
|| false === strripos($response->getContent(), '</body>')
) {
if ($response->headers->has('Content-Type') && false !== strpos($response->headers->get('Content-Type'), 'html')) {
if ($response->headers->has('Content-Type') && str_contains($response->headers->get('Content-Type'), 'html')) {
$dumper = new HtmlDumper('php://output', $this->charset);
$dumper->setDisplayOptions(array('fileLinkFormat' => $this->fileLinkFormat));
$dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
} else {
$dumper = new CliDumper('php://output', $this->charset);
if (method_exists($dumper, 'setDisplayOptions')) {
$dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
}
}
foreach ($this->data as $dump) {
@@ -126,36 +146,51 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
if ($this->stopwatch) {
$this->stopwatch->reset();
}
$this->data = array();
$this->data = [];
$this->dataCount = 0;
$this->isCollected = true;
$this->clonesCount = 0;
$this->clonesIndex = 0;
}
public function serialize()
/**
* @internal
*/
public function __sleep(): array
{
if (!$this->dataCount) {
$this->data = [];
}
if ($this->clonesCount !== $this->clonesIndex) {
return 'a:0:{}';
return [];
}
$this->data[] = $this->fileLinkFormat;
$this->data[] = $this->charset;
$ser = serialize($this->data);
$this->data = array();
$this->dataCount = 0;
$this->isCollected = true;
return $ser;
return parent::__sleep();
}
public function unserialize($data)
/**
* @internal
*/
public function __wakeup()
{
parent::unserialize($data);
parent::__wakeup();
$charset = array_pop($this->data);
$fileLinkFormat = array_pop($this->data);
$this->dataCount = \count($this->data);
self::__construct($this->stopwatch, $fileLinkFormat, $charset);
foreach ($this->data as $dump) {
if (!\is_string($dump['name']) || !\is_string($dump['file']) || !\is_int($dump['line'])) {
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
}
}
self::__construct($this->stopwatch, \is_string($fileLinkFormat) || $fileLinkFormat instanceof FileLinkFormatter ? $fileLinkFormat : null, \is_string($charset) ? $charset : null);
}
public function getDumpsCount()
@@ -165,15 +200,19 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
public function getDumps($format, $maxDepthLimit = -1, $maxItemsPerDepth = -1)
{
$data = fopen('php://memory', 'r+b');
$data = fopen('php://memory', 'r+');
if ('html' === $format) {
$dumper = new HtmlDumper($data, $this->charset);
$dumper->setDisplayOptions(array('fileLinkFormat' => $this->fileLinkFormat));
$dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
} else {
throw new \InvalidArgumentException(sprintf('Invalid dump format: %s', $format));
throw new \InvalidArgumentException(sprintf('Invalid dump format: "%s".', $format));
}
$dumps = [];
if (!$this->dataCount) {
return $this->data = [];
}
$dumps = array();
foreach ($this->data as $dump) {
$dumper->dump($dump['data']->withMaxDepth($maxDepthLimit)->withMaxItemsPerDepth($maxItemsPerDepth));
@@ -193,28 +232,25 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
public function __destruct()
{
if (0 === $this->clonesCount-- && !$this->isCollected && $this->data) {
if (0 === $this->clonesCount-- && !$this->isCollected && $this->dataCount) {
$this->clonesCount = 0;
$this->isCollected = true;
$h = headers_list();
$i = \count($h);
array_unshift($h, 'Content-Type: '.ini_get('default_mimetype'));
array_unshift($h, 'Content-Type: '.\ini_get('default_mimetype'));
while (0 !== stripos($h[$i], 'Content-Type:')) {
--$i;
}
if (isset($_SERVER['VAR_DUMPER_FORMAT'])) {
$html = 'html' === $_SERVER['VAR_DUMPER_FORMAT'];
} else {
$html = !\in_array(\PHP_SAPI, array('cli', 'phpdbg'), true) && stripos($h[$i], 'html');
}
if ($html) {
if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && stripos($h[$i], 'html')) {
$dumper = new HtmlDumper('php://output', $this->charset);
$dumper->setDisplayOptions(array('fileLinkFormat' => $this->fileLinkFormat));
$dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
} else {
$dumper = new CliDumper('php://output', $this->charset);
if (method_exists($dumper, 'setDisplayOptions')) {
$dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
}
}
foreach ($this->data as $i => $dump) {
@@ -222,12 +258,12 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
$this->doDump($dumper, $dump['data'], $dump['name'], $dump['file'], $dump['line']);
}
$this->data = array();
$this->data = [];
$this->dataCount = 0;
}
}
private function doDump(DataDumperInterface $dumper, $data, $name, $file, $line)
private function doDump(DataDumperInterface $dumper, Data $data, string $name, string $file, int $line)
{
if ($dumper instanceof CliDumper) {
$contextDumper = function ($name, $file, $line, $fmt) {
@@ -236,7 +272,7 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
$s = $this->style('meta', '%s');
$f = strip_tags($this->style('', $file));
$name = strip_tags($this->style('', $name));
if ($fmt && $link = \is_string($fmt) ? strtr($fmt, array('%f' => $file, '%l' => $line)) : $fmt->format($file, $line)) {
if ($fmt && $link = \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : $fmt->format($file, $line)) {
$name = sprintf('<a href="%s" title="%s">'.$s.'</a>', strip_tags($this->style('', $link)), $f, $name);
} else {
$name = sprintf('<abbr title="%s">'.$s.'</abbr>', $f, $name);

View File

@@ -13,40 +13,49 @@ namespace Symfony\Component\HttpKernel\DataCollector;
use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher;
use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\Service\ResetInterface;
/**
* EventDataCollector.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.4
*/
class EventDataCollector extends DataCollector implements LateDataCollectorInterface
{
protected $dispatcher;
private $requestStack;
private $currentRequest;
public function __construct(EventDispatcherInterface $dispatcher = null)
public function __construct(EventDispatcherInterface $dispatcher = null, RequestStack $requestStack = null)
{
$this->dispatcher = $dispatcher;
$this->requestStack = $requestStack;
}
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response, \Exception $exception = null)
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
{
$this->data = array(
'called_listeners' => array(),
'not_called_listeners' => array(),
'orphaned_events' => array(),
);
$this->currentRequest = $this->requestStack && $this->requestStack->getMasterRequest() !== $request ? $request : null;
$this->data = [
'called_listeners' => [],
'not_called_listeners' => [],
'orphaned_events' => [],
];
}
public function reset()
{
$this->data = array();
$this->data = [];
if ($this->dispatcher instanceof ResetInterface) {
$this->dispatcher->reset();
@@ -56,12 +65,12 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
public function lateCollect()
{
if ($this->dispatcher instanceof TraceableEventDispatcherInterface) {
$this->setCalledListeners($this->dispatcher->getCalledListeners());
$this->setNotCalledListeners($this->dispatcher->getNotCalledListeners());
$this->setCalledListeners($this->dispatcher->getCalledListeners($this->currentRequest));
$this->setNotCalledListeners($this->dispatcher->getNotCalledListeners($this->currentRequest));
}
if ($this->dispatcher instanceof TraceableEventDispatcher) {
$this->setOrphanedEvents($this->dispatcher->getOrphanedEvents());
$this->setOrphanedEvents($this->dispatcher->getOrphanedEvents($this->currentRequest));
}
$this->data = $this->cloneVar($this->data);
@@ -94,8 +103,6 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
/**
* Sets the not called listeners.
*
* @param array $listeners
*
* @see TraceableEventDispatcher
*/
public function setNotCalledListeners(array $listeners)

View File

@@ -11,7 +11,7 @@
namespace Symfony\Component\HttpKernel\DataCollector;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\ErrorHandler\Exception\FlattenException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -19,18 +19,24 @@ use Symfony\Component\HttpFoundation\Response;
* ExceptionDataCollector.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.4
*/
class ExceptionDataCollector extends DataCollector
{
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response, \Exception $exception = null)
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
{
$exception = 2 < \func_num_args() ? func_get_arg(2) : null;
if (null !== $exception) {
$this->data = array(
'exception' => FlattenException::create($exception),
);
$this->data = [
'exception' => FlattenException::createFromThrowable($exception),
];
}
}
@@ -39,7 +45,7 @@ class ExceptionDataCollector extends DataCollector
*/
public function reset()
{
$this->data = array();
$this->data = [];
}
/**
@@ -55,7 +61,7 @@ class ExceptionDataCollector extends DataCollector
/**
* Gets the exception.
*
* @return \Exception The exception
* @return \Exception|FlattenException
*/
public function getException()
{

View File

@@ -11,16 +11,16 @@
namespace Symfony\Component\HttpKernel\DataCollector;
use Symfony\Component\Debug\Exception\SilencedErrorContext;
use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
/**
* LogDataCollector.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.4
*/
class LoggerDataCollector extends DataCollector implements LateDataCollectorInterface
{
@@ -41,8 +41,10 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response, \Exception $exception = null)
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
{
$this->currentRequest = $this->requestStack && $this->requestStack->getMasterRequest() !== $request ? $request : null;
}
@@ -55,7 +57,7 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
if ($this->logger instanceof DebugLoggerInterface) {
$this->logger->clear();
}
$this->data = array();
$this->data = [];
}
/**
@@ -66,51 +68,48 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
if (null !== $this->logger) {
$containerDeprecationLogs = $this->getContainerDeprecationLogs();
$this->data = $this->computeErrorsCount($containerDeprecationLogs);
$this->data['compiler_logs'] = $this->getContainerCompilerLogs();
// get compiler logs later (only when they are needed) to improve performance
$this->data['compiler_logs'] = [];
$this->data['compiler_logs_filepath'] = $this->containerPathPrefix.'Compiler.log';
$this->data['logs'] = $this->sanitizeLogs(array_merge($this->logger->getLogs($this->currentRequest), $containerDeprecationLogs));
$this->data = $this->cloneVar($this->data);
}
$this->currentRequest = null;
}
/**
* Gets the logs.
*
* @return array An array of logs
*/
public function getLogs()
{
return isset($this->data['logs']) ? $this->data['logs'] : array();
return $this->data['logs'] ?? [];
}
public function getPriorities()
{
return isset($this->data['priorities']) ? $this->data['priorities'] : array();
return $this->data['priorities'] ?? [];
}
public function countErrors()
{
return isset($this->data['error_count']) ? $this->data['error_count'] : 0;
return $this->data['error_count'] ?? 0;
}
public function countDeprecations()
{
return isset($this->data['deprecation_count']) ? $this->data['deprecation_count'] : 0;
return $this->data['deprecation_count'] ?? 0;
}
public function countWarnings()
{
return isset($this->data['warning_count']) ? $this->data['warning_count'] : 0;
return $this->data['warning_count'] ?? 0;
}
public function countScreams()
{
return isset($this->data['scream_count']) ? $this->data['scream_count'] : 0;
return $this->data['scream_count'] ?? 0;
}
public function getCompilerLogs()
{
return isset($this->data['compiler_logs']) ? $this->data['compiler_logs'] : array();
return $this->cloneVar($this->getContainerCompilerLogs($this->data['compiler_logs_filepath'] ?? null));
}
/**
@@ -121,16 +120,20 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
return 'logger';
}
private function getContainerDeprecationLogs()
private function getContainerDeprecationLogs(): array
{
if (null === $this->containerPathPrefix || !file_exists($file = $this->containerPathPrefix.'Deprecations.log')) {
return array();
return [];
}
if ('' === $logContent = trim(file_get_contents($file))) {
return [];
}
$bootTime = filemtime($file);
$logs = array();
foreach (unserialize(file_get_contents($file)) as $log) {
$log['context'] = array('exception' => new SilencedErrorContext($log['type'], $log['file'], $log['line'], $log['trace'], $log['count']));
$logs = [];
foreach (unserialize($logContent) as $log) {
$log['context'] = ['exception' => new SilencedErrorContext($log['type'], $log['file'], $log['line'], $log['trace'], $log['count'])];
$log['timestamp'] = $bootTime;
$log['priority'] = 100;
$log['priorityName'] = 'DEBUG';
@@ -143,29 +146,29 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
return $logs;
}
private function getContainerCompilerLogs()
private function getContainerCompilerLogs(string $compilerLogsFilepath = null): array
{
if (null === $this->containerPathPrefix || !file_exists($file = $this->containerPathPrefix.'Compiler.log')) {
return array();
if (!file_exists($compilerLogsFilepath)) {
return [];
}
$logs = array();
foreach (file($file, FILE_IGNORE_NEW_LINES) as $log) {
$logs = [];
foreach (file($compilerLogsFilepath, \FILE_IGNORE_NEW_LINES) as $log) {
$log = explode(': ', $log, 2);
if (!isset($log[1]) || !preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)++$/', $log[0])) {
$log = array('Unknown Compiler Pass', implode(': ', $log));
$log = ['Unknown Compiler Pass', implode(': ', $log)];
}
$logs[$log[0]][] = array('message' => $log[1]);
$logs[$log[0]][] = ['message' => $log[1]];
}
return $logs;
}
private function sanitizeLogs($logs)
private function sanitizeLogs(array $logs)
{
$sanitizedLogs = array();
$silencedLogs = array();
$sanitizedLogs = [];
$silencedLogs = [];
foreach ($logs as $log) {
if (!$this->isSilencedOrDeprecationErrorLog($log)) {
@@ -174,7 +177,7 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
continue;
}
$message = $log['message'];
$message = '_'.$log['message'];
$exception = $log['context']['exception'];
if ($exception instanceof SilencedErrorContext) {
@@ -184,10 +187,10 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
$silencedLogs[$h] = true;
if (!isset($sanitizedLogs[$message])) {
$sanitizedLogs[$message] = $log + array(
$sanitizedLogs[$message] = $log + [
'errorCount' => 0,
'scream' => true,
);
];
}
$sanitizedLogs[$message]['errorCount'] += $exception->count;
@@ -199,10 +202,10 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
if (isset($sanitizedLogs[$errorId])) {
++$sanitizedLogs[$errorId]['errorCount'];
} else {
$log += array(
$log += [
'errorCount' => 1,
'scream' => false,
);
];
$sanitizedLogs[$errorId] = $log;
}
@@ -211,7 +214,7 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
return array_values($sanitizedLogs);
}
private function isSilencedOrDeprecationErrorLog(array $log)
private function isSilencedOrDeprecationErrorLog(array $log): bool
{
if (!isset($log['context']['exception'])) {
return false;
@@ -223,32 +226,32 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
return true;
}
if ($exception instanceof \ErrorException && \in_array($exception->getSeverity(), array(E_DEPRECATED, E_USER_DEPRECATED), true)) {
if ($exception instanceof \ErrorException && \in_array($exception->getSeverity(), [\E_DEPRECATED, \E_USER_DEPRECATED], true)) {
return true;
}
return false;
}
private function computeErrorsCount(array $containerDeprecationLogs)
private function computeErrorsCount(array $containerDeprecationLogs): array
{
$silencedLogs = array();
$count = array(
$silencedLogs = [];
$count = [
'error_count' => $this->logger->countErrors($this->currentRequest),
'deprecation_count' => 0,
'warning_count' => 0,
'scream_count' => 0,
'priorities' => array(),
);
'priorities' => [],
];
foreach ($this->logger->getLogs($this->currentRequest) as $log) {
if (isset($count['priorities'][$log['priority']])) {
++$count['priorities'][$log['priority']]['count'];
} else {
$count['priorities'][$log['priority']] = array(
$count['priorities'][$log['priority']] = [
'count' => 1,
'name' => $log['priorityName'],
);
];
}
if ('WARNING' === $log['priorityName']) {
++$count['warning_count'];

View File

@@ -18,6 +18,8 @@ use Symfony\Component\HttpFoundation\Response;
* MemoryDataCollector.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.4
*/
class MemoryDataCollector extends DataCollector implements LateDataCollectorInterface
{
@@ -28,8 +30,10 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response, \Exception $exception = null)
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
{
$this->updateMemoryUsage();
}
@@ -39,10 +43,10 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte
*/
public function reset()
{
$this->data = array(
$this->data = [
'memory' => 0,
'memory_limit' => $this->convertToBytes(ini_get('memory_limit')),
);
'memory_limit' => $this->convertToBytes(\ini_get('memory_limit')),
];
}
/**
@@ -89,7 +93,10 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte
return 'memory';
}
private function convertToBytes($memoryLimit)
/**
* @return int|float
*/
private function convertToBytes(string $memoryLimit)
{
if ('-1' === $memoryLimit) {
return -1;
@@ -97,9 +104,9 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte
$memoryLimit = strtolower($memoryLimit);
$max = strtolower(ltrim($memoryLimit, '+'));
if (0 === strpos($max, '0x')) {
if (str_starts_with($max, '0x')) {
$max = \intval($max, 16);
} elseif (0 === strpos($max, '0')) {
} elseif (str_starts_with($max, '0')) {
$max = \intval($max, 8);
} else {
$max = (int) $max;

View File

@@ -22,6 +22,8 @@ use Symfony\Component\HttpKernel\KernelEvents;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.4
*/
class RequestDataCollector extends DataCollector implements EventSubscriberInterface, LateDataCollectorInterface
{
@@ -34,11 +36,13 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response, \Exception $exception = null)
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.
$attributes = array();
$attributes = [];
$route = '';
foreach ($request->attributes->all() as $key => $value) {
if ('_route' === $key) {
@@ -49,23 +53,16 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
}
}
$content = null;
try {
$content = $request->getContent();
} catch (\LogicException $e) {
// the user already got the request content as a resource
$content = false;
}
$content = $request->getContent();
$sessionMetadata = array();
$sessionAttributes = array();
$session = null;
$flashes = array();
$sessionMetadata = [];
$sessionAttributes = [];
$flashes = [];
if ($request->hasSession()) {
$session = $request->getSession();
if ($session->isStarted()) {
$sessionMetadata['Created'] = date(DATE_RFC822, $session->getMetadataBag()->getCreated());
$sessionMetadata['Last used'] = date(DATE_RFC822, $session->getMetadataBag()->getLastUsed());
$sessionMetadata['Created'] = date(\DATE_RFC822, $session->getMetadataBag()->getCreated());
$sessionMetadata['Last used'] = date(\DATE_RFC822, $session->getMetadataBag()->getLastUsed());
$sessionMetadata['Lifetime'] = $session->getMetadataBag()->getLifetime();
$sessionAttributes = $session->all();
$flashes = $session->getFlashBag()->peekAll();
@@ -74,24 +71,24 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
$statusCode = $response->getStatusCode();
$responseCookies = array();
$responseCookies = [];
foreach ($response->headers->getCookies() as $cookie) {
$responseCookies[$cookie->getName()] = $cookie;
}
$dotenvVars = array();
foreach (explode(',', getenv('SYMFONY_DOTENV_VARS')) as $name) {
if ('' !== $name && false !== $value = getenv($name)) {
$dotenvVars[$name] = $value;
$dotenvVars = [];
foreach (explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? $_ENV['SYMFONY_DOTENV_VARS'] ?? '') as $name) {
if ('' !== $name && isset($_ENV[$name])) {
$dotenvVars[$name] = $_ENV[$name];
}
}
$this->data = array(
$this->data = [
'method' => $request->getMethod(),
'format' => $request->getRequestFormat(),
'content' => $content,
'content_type' => $response->headers->get('Content-Type', 'text/html'),
'status_text' => isset(Response::$statusTexts[$statusCode]) ? Response::$statusTexts[$statusCode] : '',
'status_text' => Response::$statusTexts[$statusCode] ?? '',
'status_code' => $statusCode,
'request_query' => $request->query->all(),
'request_request' => $request->request->all(),
@@ -110,7 +107,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
'controller' => 'n/a',
'locale' => $request->getLocale(),
'dotenv_vars' => $dotenvVars,
);
];
if (isset($this->data['request_headers']['php-auth-pw'])) {
$this->data['request_headers']['php-auth-pw'] = '******';
@@ -147,14 +144,14 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
if ($response->isRedirect()) {
$response->headers->setCookie(new Cookie(
'sf_redirect',
json_encode(array(
json_encode([
'token' => $response->headers->get('x-debug-token'),
'route' => $request->attributes->get('_route', 'n/a'),
'method' => $request->getMethod(),
'controller' => $this->parseController($request->attributes->get('_controller')),
'status_code' => $statusCode,
'status_text' => Response::$statusTexts[(int) $statusCode],
)),
'status_text' => Response::$statusTexts[$statusCode],
]),
0, '/', null, $request->isSecure(), true, false, 'lax'
));
}
@@ -173,7 +170,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
public function reset()
{
$this->data = array();
$this->data = [];
$this->controllers = new \SplObjectStorage();
}
@@ -252,6 +249,18 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
return $this->data['content'];
}
public function isJsonRequest()
{
return 1 === preg_match('{^application/(?:\w+\++)*json$}i', $this->data['request_headers']['content-type']);
}
public function getPrettyJson()
{
$decoded = json_decode($this->getContent());
return \JSON_ERROR_NONE === json_last_error() ? json_encode($decoded, \JSON_PRETTY_PRINT) : null;
}
public function getContentType()
{
return $this->data['content_type'];
@@ -308,7 +317,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
*/
public function getRouteParams()
{
return isset($this->data['request_attributes']['_route_params']) ? $this->data['request_attributes']['_route_params']->getValue() : array();
return isset($this->data['request_attributes']['_route_params']) ? $this->data['request_attributes']['_route_params']->getValue() : [];
}
/**
@@ -330,19 +339,25 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
*/
public function getRedirect()
{
return isset($this->data['redirect']) ? $this->data['redirect'] : false;
return $this->data['redirect'] ?? false;
}
public function getForwardToken()
{
return isset($this->data['forward_token']) ? $this->data['forward_token'] : null;
return $this->data['forward_token'] ?? null;
}
/**
* @final since Symfony 4.3
*/
public function onKernelController(FilterControllerEvent $event)
{
$this->controllers[$event->getRequest()] = $event->getController();
}
/**
* @final since Symfony 4.3
*/
public function onKernelResponse(FilterResponseEvent $event)
{
if (!$event->isMasterRequest()) {
@@ -356,10 +371,10 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
public static function getSubscribedEvents()
{
return array(
return [
KernelEvents::CONTROLLER => 'onKernelController',
KernelEvents::RESPONSE => 'onKernelResponse',
);
];
}
/**
@@ -373,13 +388,13 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
/**
* Parse a controller.
*
* @param mixed $controller The controller to parse
* @param string|object|array|null $controller The controller to parse
*
* @return array|string An array of controller data or a simple string
*/
protected function parseController($controller)
{
if (\is_string($controller) && false !== strpos($controller, '::')) {
if (\is_string($controller) && str_contains($controller, '::')) {
$controller = explode('::', $controller);
}
@@ -387,21 +402,21 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
try {
$r = new \ReflectionMethod($controller[0], $controller[1]);
return array(
return [
'class' => \is_object($controller[0]) ? \get_class($controller[0]) : $controller[0],
'method' => $controller[1],
'file' => $r->getFileName(),
'line' => $r->getStartLine(),
);
];
} catch (\ReflectionException $e) {
if (\is_callable($controller)) {
// using __call or __callStatic
return array(
return [
'class' => \is_object($controller[0]) ? \get_class($controller[0]) : $controller[0],
'method' => $controller[1],
'file' => 'n/a',
'line' => 'n/a',
);
];
}
}
}
@@ -409,14 +424,14 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
if ($controller instanceof \Closure) {
$r = new \ReflectionFunction($controller);
$controller = array(
$controller = [
'class' => $r->getName(),
'method' => null,
'file' => $r->getFileName(),
'line' => $r->getStartLine(),
);
];
if (false !== strpos($r->name, '{closure}')) {
if (str_contains($r->name, '{closure}')) {
return $controller;
}
$controller['method'] = $r->name;
@@ -433,12 +448,12 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
if (\is_object($controller)) {
$r = new \ReflectionClass($controller);
return array(
return [
'class' => $r->getName(),
'method' => null,
'file' => $r->getFileName(),
'line' => $r->getStartLine(),
);
];
}
return \is_string($controller) ? $controller : 'n/a';

View File

@@ -17,8 +17,6 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
/**
* RouterDataCollector.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class RouterDataCollector extends DataCollector
@@ -35,8 +33,12 @@ class RouterDataCollector extends DataCollector
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*
* @final since Symfony 4.4
*/
public function collect(Request $request, Response $response, \Exception $exception = null)
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
{
if ($response instanceof RedirectResponse) {
$this->data['redirect'] = true;
@@ -54,11 +56,11 @@ class RouterDataCollector extends DataCollector
{
$this->controllers = new \SplObjectStorage();
$this->data = array(
$this->data = [
'redirect' => false,
'url' => null,
'route' => null,
);
];
}
protected function guessRoute(Request $request, $controller)
@@ -68,6 +70,8 @@ class RouterDataCollector extends DataCollector
/**
* Remembers the controller associated to each request.
*
* @final since Symfony 4.3
*/
public function onKernelController(FilterControllerEvent $event)
{

View File

@@ -15,11 +15,12 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Component\Stopwatch\StopwatchEvent;
/**
* TimeDataCollector.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.4
*/
class TimeDataCollector extends DataCollector implements LateDataCollectorInterface
{
@@ -34,8 +35,10 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response, \Exception $exception = null)
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
{
if (null !== $this->kernel) {
$startTime = $this->kernel->getStartTime();
@@ -43,11 +46,12 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
$startTime = $request->server->get('REQUEST_TIME_FLOAT');
}
$this->data = array(
'token' => $response->headers->get('X-Debug-Token'),
$this->data = [
'token' => $request->attributes->get('_stopwatch_token'),
'start_time' => $startTime * 1000,
'events' => array(),
);
'events' => [],
'stopwatch_installed' => class_exists(Stopwatch::class, false),
];
}
/**
@@ -55,7 +59,7 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
*/
public function reset()
{
$this->data = array();
$this->data = [];
if (null !== $this->stopwatch) {
$this->stopwatch->reset();
@@ -76,7 +80,7 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
/**
* Sets the request events.
*
* @param array $events The request events
* @param StopwatchEvent[] $events The request events
*/
public function setEvents(array $events)
{
@@ -90,7 +94,7 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
/**
* Gets the request events.
*
* @return array The request events
* @return StopwatchEvent[] The request events
*/
public function getEvents()
{
@@ -132,13 +136,21 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
/**
* Gets the request time.
*
* @return int The time
* @return float
*/
public function getStartTime()
{
return $this->data['start_time'];
}
/**
* @return bool whether or not the stopwatch component is installed
*/
public function isStopwatchInstalled()
{
return $this->data['stopwatch_installed'];
}
/**
* {@inheritdoc}
*/

View File

@@ -13,15 +13,16 @@ namespace Symfony\Component\HttpKernel\Debug;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\Exception\ExceptionInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
/**
* Formats debug file links.
*
* @author Jérémy Romey <jeremy@free-agent.fr>
*
* @final since Symfony 4.3
*/
class FileLinkFormatter implements \Serializable
class FileLinkFormatter
{
private $fileLinkFormat;
private $requestStack;
@@ -29,14 +30,14 @@ class FileLinkFormatter implements \Serializable
private $urlFormat;
/**
* @param string|\Closure $urlFormat the URL format, or a closure that returns it on-demand
* @param string|array|null $fileLinkFormat
* @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)
{
$fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
if ($fileLinkFormat && !\is_array($fileLinkFormat)) {
if (!\is_array($fileLinkFormat) && $fileLinkFormat = $fileLinkFormat ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format')) {
$i = strpos($f = $fileLinkFormat, '&', max(strrpos($f, '%f'), strrpos($f, '%l'))) ?: \strlen($f);
$fileLinkFormat = array(substr($f, 0, $i)) + preg_split('/&([^>]++)>/', substr($f, $i), -1, PREG_SPLIT_DELIM_CAPTURE);
$fileLinkFormat = [substr($f, 0, $i)] + preg_split('/&([^>]++)>/', substr($f, $i), -1, \PREG_SPLIT_DELIM_CAPTURE);
}
$this->fileLinkFormat = $fileLinkFormat;
@@ -49,26 +50,26 @@ class FileLinkFormatter implements \Serializable
{
if ($fmt = $this->getFileLinkFormat()) {
for ($i = 1; isset($fmt[$i]); ++$i) {
if (0 === strpos($file, $k = $fmt[$i++])) {
if (str_starts_with($file, $k = $fmt[$i++])) {
$file = substr_replace($file, $fmt[$i], 0, \strlen($k));
break;
}
}
return strtr($fmt[0], array('%f' => $file, '%l' => $line));
return strtr($fmt[0], ['%f' => $file, '%l' => $line]);
}
return false;
}
public function serialize()
/**
* @internal
*/
public function __sleep(): array
{
return serialize($this->getFileLinkFormat());
}
$this->fileLinkFormat = $this->getFileLinkFormat();
public function unserialize($serialized)
{
$this->fileLinkFormat = unserialize($serialized, array('allowed_classes' => false));
return ['fileLinkFormat'];
}
/**
@@ -78,7 +79,7 @@ class FileLinkFormatter implements \Serializable
{
try {
return $router->generate($routeName).$queryString;
} catch (ExceptionInterface $e) {
} catch (\Throwable $e) {
return null;
}
}
@@ -88,18 +89,18 @@ class FileLinkFormatter implements \Serializable
if ($this->fileLinkFormat) {
return $this->fileLinkFormat;
}
if ($this->requestStack && $this->baseDir && $this->urlFormat) {
$request = $this->requestStack->getMasterRequest();
if ($request instanceof Request) {
if ($this->urlFormat instanceof \Closure && !$this->urlFormat = \call_user_func($this->urlFormat)) {
return;
}
return array(
$request->getSchemeAndHttpHost().$request->getBasePath().$this->urlFormat,
if ($request instanceof Request && (!$this->urlFormat instanceof \Closure || $this->urlFormat = ($this->urlFormat)())) {
return [
$request->getSchemeAndHttpHost().$this->urlFormat,
$this->baseDir.\DIRECTORY_SEPARATOR, '',
);
];
}
}
return null;
}
}

View File

@@ -12,7 +12,6 @@
namespace Symfony\Component\HttpKernel\Debug;
use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher as BaseTraceableEventDispatcher;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\HttpKernel\KernelEvents;
/**
@@ -27,10 +26,11 @@ class TraceableEventDispatcher extends BaseTraceableEventDispatcher
/**
* {@inheritdoc}
*/
protected function preDispatch($eventName, Event $event)
protected function beforeDispatch(string $eventName, $event)
{
switch ($eventName) {
case KernelEvents::REQUEST:
$event->getRequest()->attributes->set('_stopwatch_token', substr(hash('sha256', uniqid(mt_rand(), true)), 0, 6));
$this->stopwatch->openSection();
break;
case KernelEvents::VIEW:
@@ -41,14 +41,17 @@ class TraceableEventDispatcher extends BaseTraceableEventDispatcher
}
break;
case KernelEvents::TERMINATE:
$token = $event->getResponse()->headers->get('X-Debug-Token');
$sectionId = $event->getRequest()->attributes->get('_stopwatch_token');
if (null === $sectionId) {
break;
}
// There is a very special case when using built-in AppCache class as kernel wrapper, in the case
// of an ESI request leading to a `stale` response [B] inside a `fresh` cached response [A].
// In this case, `$token` contains the [B] debug token, but the open `stopwatch` section ID
// is equal to the [A] debug token. Trying to reopen section with the [B] token throws an exception
// which must be caught.
try {
$this->stopwatch->openSection($token);
$this->stopwatch->openSection($sectionId);
} catch (\LogicException $e) {
}
break;
@@ -58,22 +61,28 @@ class TraceableEventDispatcher extends BaseTraceableEventDispatcher
/**
* {@inheritdoc}
*/
protected function postDispatch($eventName, Event $event)
protected function afterDispatch(string $eventName, $event)
{
switch ($eventName) {
case KernelEvents::CONTROLLER_ARGUMENTS:
$this->stopwatch->start('controller', 'section');
break;
case KernelEvents::RESPONSE:
$token = $event->getResponse()->headers->get('X-Debug-Token');
$this->stopwatch->stopSection($token);
$sectionId = $event->getRequest()->attributes->get('_stopwatch_token');
if (null === $sectionId) {
break;
}
$this->stopwatch->stopSection($sectionId);
break;
case KernelEvents::TERMINATE:
// In the special case described in the `preDispatch` method above, the `$token` section
// does not exist, then closing it throws an exception which must be caught.
$token = $event->getResponse()->headers->get('X-Debug-Token');
$sectionId = $event->getRequest()->attributes->get('_stopwatch_token');
if (null === $sectionId) {
break;
}
try {
$this->stopwatch->stopSection($token);
$this->stopwatch->stopSection($sectionId);
} catch (\LogicException $e) {
}
break;

View File

@@ -12,9 +12,10 @@
namespace Symfony\Component\HttpKernel\DependencyInjection;
use Composer\Autoload\ClassLoader;
use Symfony\Component\Debug\DebugClassLoader;
use Symfony\Component\Debug\DebugClassLoader as LegacyDebugClassLoader;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\ErrorHandler\DebugClassLoader;
use Symfony\Component\HttpKernel\Kernel;
/**
@@ -54,16 +55,14 @@ class AddAnnotatedClassesToCachePass implements CompilerPassInterface
*
* @param array $patterns The class patterns to expand
* @param array $classes The existing classes to match against the patterns
*
* @return array A list of classes derivated from the patterns
*/
private function expandClasses(array $patterns, array $classes)
private function expandClasses(array $patterns, array $classes): array
{
$expanded = array();
$expanded = [];
// Explicit classes declared in the patterns are returned directly
foreach ($patterns as $key => $pattern) {
if ('\\' !== substr($pattern, -1) && false === strpos($pattern, '*')) {
if (!str_ends_with($pattern, '\\') && !str_contains($pattern, '*')) {
unset($patterns[$key]);
$expanded[] = ltrim($pattern, '\\');
}
@@ -83,16 +82,16 @@ class AddAnnotatedClassesToCachePass implements CompilerPassInterface
return array_unique($expanded);
}
private function getClassesInComposerClassMaps()
private function getClassesInComposerClassMaps(): array
{
$classes = array();
$classes = [];
foreach (spl_autoload_functions() as $function) {
if (!\is_array($function)) {
continue;
}
if ($function[0] instanceof DebugClassLoader) {
if ($function[0] instanceof DebugClassLoader || $function[0] instanceof LegacyDebugClassLoader) {
$function = $function[0]->getClassLoader();
}
@@ -104,16 +103,16 @@ class AddAnnotatedClassesToCachePass implements CompilerPassInterface
return array_keys($classes);
}
private function patternsToRegexps($patterns)
private function patternsToRegexps(array $patterns): array
{
$regexps = array();
$regexps = [];
foreach ($patterns as $pattern) {
// Escape user input
$regex = preg_quote(ltrim($pattern, '\\'));
// Wildcards * and **
$regex = strtr($regex, array('\\*\\*' => '.*?', '\\*' => '[^\\\\]*?'));
$regex = strtr($regex, ['\\*\\*' => '.*?', '\\*' => '[^\\\\]*?']);
// If this class does not end by a slash, anchor the end
if ('\\' !== substr($regex, -1)) {
@@ -126,12 +125,12 @@ class AddAnnotatedClassesToCachePass implements CompilerPassInterface
return $regexps;
}
private function matchAnyRegexps($class, $regexps)
private function matchAnyRegexps(string $class, array $regexps): bool
{
$blacklisted = false !== strpos($class, 'Test');
$isTest = str_contains($class, 'Test');
foreach ($regexps as $regex) {
if ($blacklisted && false === strpos($regex, 'Test')) {
if ($isTest && !str_contains($regex, 'Test')) {
continue;
}

View File

@@ -52,7 +52,7 @@ class ControllerArgumentValueResolverPass implements CompilerPassInterface
$id = (string) $resolverReference;
$container->register("debug.$id", TraceableValueResolver::class)
->setDecoratedService($id)
->setArguments(array(new Reference("debug.$id.inner"), new Reference($this->traceableResolverStopwatch)));
->setArguments([new Reference("debug.$id.inner"), new Reference($this->traceableResolverStopwatch)]);
}
}

View File

@@ -20,7 +20,7 @@ use Symfony\Component\DependencyInjection\Extension\Extension as BaseExtension;
*/
abstract class Extension extends BaseExtension
{
private $annotatedClasses = array();
private $annotatedClasses = [];
/**
* Gets the annotated classes to cache.

View File

@@ -41,7 +41,7 @@ class FragmentRendererPass implements CompilerPassInterface
}
$definition = $container->getDefinition($this->handlerService);
$renderers = array();
$renderers = [];
foreach ($container->findTaggedServiceIds($this->rendererTag, true) as $id => $tags) {
$def = $container->getDefinition($id);
$class = $container->getParameterBag()->resolveValue($def->getClass());

View File

@@ -23,19 +23,19 @@ use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
class LazyLoadingFragmentHandler extends FragmentHandler
{
private $container;
private $initialized = array();
private $initialized = [];
public function __construct(ContainerInterface $container, RequestStack $requestStack, bool $debug = false)
{
$this->container = $container;
parent::__construct($requestStack, array(), $debug);
parent::__construct($requestStack, [], $debug);
}
/**
* {@inheritdoc}
*/
public function render($uri, $renderer = 'inline', array $options = array())
public function render($uri, $renderer = 'inline', array $options = [])
{
if (!isset($this->initialized[$renderer]) && $this->container->has($renderer)) {
$this->addRenderer($this->container->get($renderer));

View File

@@ -32,7 +32,7 @@ class MergeExtensionConfigurationPass extends BaseMergeExtensionConfigurationPas
{
foreach ($this->extensions as $extension) {
if (!\count($container->getExtensionConfig($extension))) {
$container->loadFromExtension($extension, array());
$container->loadFromExtension($extension, []);
}
}

View File

@@ -34,22 +34,24 @@ 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')
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')
{
$this->resolverServiceId = $resolverServiceId;
$this->controllerTag = $controllerTag;
$this->controllerLocator = $controllerLocator;
$this->notTaggedControllerResolverServiceId = $notTaggedControllerResolverServiceId;
}
public function process(ContainerBuilder $container)
{
if (false === $container->hasDefinition($this->resolverServiceId)) {
if (false === $container->hasDefinition($this->resolverServiceId) && false === $container->hasDefinition($this->notTaggedControllerResolverServiceId)) {
return;
}
$parameterBag = $container->getParameterBag();
$controllers = array();
$controllers = [];
foreach ($container->findTaggedServiceIds($this->controllerTag, true) as $id => $tags) {
$def = $container->getDefinition($id);
@@ -72,14 +74,14 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
$isContainerAware = $r->implementsInterface(ContainerAwareInterface::class) || is_subclass_of($class, AbstractController::class);
// get regular public methods
$methods = array();
$arguments = array();
$methods = [];
$arguments = [];
foreach ($r->getMethods(\ReflectionMethod::IS_PUBLIC) as $r) {
if ('setContainer' === $r->name && $isContainerAware) {
continue;
}
if (!$r->isConstructor() && !$r->isDestructor() && !$r->isAbstract()) {
$methods[strtolower($r->name)] = array($r, $r->getParameters());
$methods[strtolower($r->name)] = [$r, $r->getParameters()];
}
}
@@ -89,15 +91,15 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
$autowire = true;
continue;
}
foreach (array('action', 'argument', 'id') as $k) {
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 "%s" %s for service "%s".', $k, $this->controllerTag, 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));
}
list($r, $parameters) = $methods[$action];
[$r, $parameters] = $methods[$action];
$found = false;
foreach ($parameters as $p) {
@@ -115,14 +117,14 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
}
}
foreach ($methods as list($r, $parameters)) {
foreach ($methods as [$r, $parameters]) {
/** @var \ReflectionMethod $r */
// create a per-method map of argument-names to service/type-references
$args = array();
$args = [];
foreach ($parameters as $p) {
/** @var \ReflectionParameter $p */
$type = ltrim($target = ProxyHelper::getTypeHint($r, $p), '\\');
$type = ltrim($target = (string) ProxyHelper::getTypeHint($r, $p), '\\');
$invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
if (isset($arguments[$r->name][$p->name])) {
@@ -137,14 +139,14 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
} elseif (isset($bindings[$bindingName = $type.' $'.$p->name]) || isset($bindings[$bindingName = '$'.$p->name]) || isset($bindings[$bindingName = $type])) {
$binding = $bindings[$bindingName];
list($bindingValue, $bindingId) = $binding->getValues();
$binding->setValues(array($bindingValue, $bindingId, true));
[$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(array($bindingValue));
->addArgument([$bindingValue]);
} else {
$args[$p->name] = $bindingValue;
}
@@ -152,6 +154,9 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
continue;
} elseif (!$type || !$autowire || '\\' !== $target[0]) {
continue;
} elseif (is_subclass_of($type, \UnitEnum::class)) {
// do not attempt to register enum typed arguments if not already present in bindings
continue;
} elseif (!$p->allowsNull()) {
$invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE;
}
@@ -181,8 +186,17 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
}
}
$container->getDefinition($this->resolverServiceId)
->replaceArgument(0, $controllerLocatorRef = ServiceLocatorTagPass::register($container, $controllers));
$controllerLocatorRef = ServiceLocatorTagPass::register($container, $controllers);
if ($container->hasDefinition($this->resolverServiceId)) {
$container->getDefinition($this->resolverServiceId)
->replaceArgument(0, $controllerLocatorRef);
}
if ($container->hasDefinition($this->notTaggedControllerResolverServiceId)) {
$container->getDefinition($this->notTaggedControllerResolverServiceId)
->replaceArgument(0, $controllerLocatorRef);
}
$container->setAlias($this->controllerLocator, (string) $controllerLocatorRef);
}

View File

@@ -0,0 +1,58 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\DependencyInjection;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* Register all services that have the "kernel.locale_aware" tag into the listener.
*
* @author Pierre Bobiet <pierrebobiet@gmail.com>
*/
class RegisterLocaleAwareServicesPass implements CompilerPassInterface
{
private $listenerServiceId;
private $localeAwareTag;
public function __construct(string $listenerServiceId = 'locale_aware_listener', string $localeAwareTag = 'kernel.locale_aware')
{
$this->listenerServiceId = $listenerServiceId;
$this->localeAwareTag = $localeAwareTag;
}
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition($this->listenerServiceId)) {
return;
}
$services = [];
foreach ($container->findTaggedServiceIds($this->localeAwareTag) as $id => $tags) {
$services[] = new Reference($id);
}
if (!$services) {
$container->removeDefinition($this->listenerServiceId);
return;
}
$container
->getDefinition($this->listenerServiceId)
->setArgument(0, new IteratorArgument($services))
;
}
}

View File

@@ -42,9 +42,9 @@ class RemoveEmptyControllerArgumentLocatorsPass implements CompilerPassInterface
} else {
// any methods listed for call-at-instantiation cannot be actions
$reason = false;
list($id, $action) = explode('::', $controller);
[$id, $action] = explode('::', $controller);
$controllerDef = $container->getDefinition($id);
foreach ($controllerDef->getMethodCalls() as list($method)) {
foreach ($controllerDef->getMethodCalls() as [$method]) {
if (0 === strcasecmp($action, $method)) {
$reason = sprintf('Removing method "%s" of service "%s" from controller candidates: the method is called at instantiation, thus cannot be an action.', $action, $id);
break;

View File

@@ -39,20 +39,25 @@ class ResettableServicePass implements CompilerPassInterface
return;
}
$services = $methods = array();
$services = $methods = [];
foreach ($container->findTaggedServiceIds($this->tagName, true) as $id => $tags) {
$services[$id] = new Reference($id, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE);
$attributes = $tags[0];
if (!isset($attributes['method'])) {
throw new RuntimeException(sprintf('Tag %s requires the "method" attribute to be set.', $this->tagName));
foreach ($tags as $attributes) {
if (!isset($attributes['method'])) {
throw new RuntimeException(sprintf('Tag "%s" requires the "method" attribute to be set.', $this->tagName));
}
if (!isset($methods[$id])) {
$methods[$id] = [];
}
$methods[$id][] = $attributes['method'];
}
$methods[$id] = $attributes['method'];
}
if (empty($services)) {
if (!$services) {
$container->removeAlias('services_resetter');
$container->removeDefinition('services_resetter');

View File

@@ -35,7 +35,9 @@ class ServicesResetter implements ResetInterface
public function reset()
{
foreach ($this->resettableServices as $id => $service) {
$service->{$this->resetMethods[$id]}();
foreach ((array) $this->resetMethods[$id] as $resetMethod) {
$service->$resetMethod();
}
}
}
}

View File

@@ -0,0 +1,30 @@
<?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\Event;
/**
* Allows filtering of controller arguments.
*
* You can call getController() to retrieve the controller and getArguments
* to retrieve the current arguments. With setArguments() you can replace
* arguments that are used to call the controller.
*
* Arguments set in the event must be compatible with the signature of the
* controller.
*
* @author Christophe Coevoet <stof@notk.org>
*
* @final since Symfony 4.4
*/
class ControllerArgumentsEvent extends FilterControllerArgumentsEvent
{
}

View File

@@ -0,0 +1,29 @@
<?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\Event;
/**
* Allows filtering of a controller callable.
*
* You can call getController() to retrieve the current controller. With
* setController() you can set a new controller that is used in the processing
* of the request.
*
* Controllers should be callables.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @final since Symfony 4.4
*/
class ControllerEvent extends FilterControllerEvent
{
}

View File

@@ -0,0 +1,31 @@
<?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\Event;
/**
* Allows to create a response for a thrown exception.
*
* Call setResponse() to set the response that will be returned for the
* current request. The propagation of this event is stopped as soon as a
* response is set.
*
* You can also call setThrowable() to replace the thrown exception. This
* exception will be thrown if no response is set during processing of this
* event.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @final since Symfony 4.4
*/
class ExceptionEvent extends GetResponseForExceptionEvent
{
}

View File

@@ -15,16 +15,7 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Allows filtering of controller arguments.
*
* You can call getController() to retrieve the controller and getArguments
* to retrieve the current arguments. With setArguments() you can replace
* arguments that are used to call the controller.
*
* Arguments set in the event must be compatible with the signature of the
* controller.
*
* @author Christophe Coevoet <stof@notk.org>
* @deprecated since Symfony 4.3, use ControllerArgumentsEvent instead
*/
class FilterControllerArgumentsEvent extends FilterControllerEvent
{

View File

@@ -15,15 +15,7 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Allows filtering of a controller callable.
*
* You can call getController() to retrieve the current controller. With
* setController() you can set a new controller that is used in the processing
* of the request.
*
* Controllers should be callables.
*
* @author Bernhard Schussek <bschussek@gmail.com>
* @deprecated since Symfony 4.3, use ControllerEvent instead
*/
class FilterControllerEvent extends KernelEvent
{

View File

@@ -16,13 +16,7 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Allows to filter a Response object.
*
* You can call getResponse() to retrieve the current response. With
* setResponse() you can set a new response that will be returned to the
* browser.
*
* @author Bernhard Schussek <bschussek@gmail.com>
* @deprecated since Symfony 4.3, use ResponseEvent instead
*/
class FilterResponseEvent extends KernelEvent
{

View File

@@ -15,6 +15,8 @@ namespace Symfony\Component\HttpKernel\Event;
* Triggered whenever a request is fully processed.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*
* @final since Symfony 4.4
*/
class FinishRequestEvent extends KernelEvent
{

View File

@@ -14,13 +14,7 @@ namespace Symfony\Component\HttpKernel\Event;
use Symfony\Component\HttpFoundation\Response;
/**
* Allows to create a response for a request.
*
* Call setResponse() to set the response that will be returned for the
* current request. The propagation of this event is stopped as soon as a
* response is set.
*
* @author Bernhard Schussek <bschussek@gmail.com>
* @deprecated since Symfony 4.3, use RequestEvent instead
*/
class GetResponseEvent extends KernelEvent
{

View File

@@ -15,15 +15,9 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Allows to create a response for the return value of a controller.
*
* Call setResponse() to set the response that will be returned for the
* current request. The propagation of this event is stopped as soon as a
* response is set.
*
* @author Bernhard Schussek <bschussek@gmail.com>
* @deprecated since Symfony 4.3, use ViewEvent instead
*/
class GetResponseForControllerResultEvent extends GetResponseEvent
class GetResponseForControllerResultEvent extends RequestEvent
{
/**
* The return value of the controller.

View File

@@ -11,63 +11,64 @@
namespace Symfony\Component\HttpKernel\Event;
use Symfony\Component\Debug\Exception\FatalThrowableError;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Allows to create a response for a thrown exception.
*
* Call setResponse() to set the response that will be returned for the
* current request. The propagation of this event is stopped as soon as a
* response is set.
*
* You can also call setException() to replace the thrown exception. This
* exception will be thrown if no response is set during processing of this
* event.
*
* @author Bernhard Schussek <bschussek@gmail.com>
* @deprecated since Symfony 4.3, use ExceptionEvent instead
*/
class GetResponseForExceptionEvent extends GetResponseEvent
class GetResponseForExceptionEvent extends RequestEvent
{
/**
* The exception object.
*
* @var \Exception
*/
private $throwable;
private $exception;
/**
* @var bool
*/
private $allowCustomResponseCode = false;
public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, \Exception $e)
public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, \Throwable $e)
{
parent::__construct($kernel, $request, $requestType);
$this->setException($e);
$this->setThrowable($e);
}
/**
* Returns the thrown exception.
*
* @return \Exception The thrown exception
*/
public function getException()
public function getThrowable(): \Throwable
{
return $this->exception;
return $this->throwable;
}
/**
* Replaces the thrown exception.
*
* This exception will be thrown if no response is set in the event.
*/
public function setThrowable(\Throwable $exception): void
{
$this->exception = null;
$this->throwable = $exception;
}
/**
* @deprecated since Symfony 4.4, use getThrowable instead
*
* @return \Exception The thrown exception
*/
public function getException()
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.4, use "getThrowable()" instead.', __METHOD__), \E_USER_DEPRECATED);
return $this->exception ?? $this->exception = $this->throwable instanceof \Exception ? $this->throwable : new FatalThrowableError($this->throwable);
}
/**
* @deprecated since Symfony 4.4, use setThrowable instead
*
* @param \Exception $exception The thrown exception
*/
public function setException(\Exception $exception)
{
$this->exception = $exception;
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.4, use "setThrowable()" instead.', __METHOD__), \E_USER_DEPRECATED);
$this->throwable = $this->exception = $exception;
}
/**

View File

@@ -27,10 +27,8 @@ class KernelEvent extends Event
private $requestType;
/**
* @param HttpKernelInterface $kernel The kernel in which this event was thrown
* @param Request $request The request the kernel is currently processing
* @param int $requestType The request type the kernel is currently processing; one of
* HttpKernelInterface::MASTER_REQUEST or HttpKernelInterface::SUB_REQUEST
* @param int $requestType The request type the kernel is currently processing; one of
* HttpKernelInterface::MASTER_REQUEST or HttpKernelInterface::SUB_REQUEST
*/
public function __construct(HttpKernelInterface $kernel, Request $request, ?int $requestType)
{

View File

@@ -16,12 +16,7 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Allows to execute logic after a response was sent.
*
* Since it's only triggered on master requests, the `getRequestType()` method
* will always return the value of `HttpKernelInterface::MASTER_REQUEST`.
*
* @author Jordi Boggiano <j.boggiano@seld.be>
* @deprecated since Symfony 4.3, use TerminateEvent instead
*/
class PostResponseEvent extends KernelEvent
{

View File

@@ -0,0 +1,25 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Event;
/**
* Allows to create a response for a request.
*
* Call setResponse() to set the response that will be returned for the
* current request. The propagation of this event is stopped as soon as a
* response is set.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class RequestEvent extends GetResponseEvent
{
}

View File

@@ -0,0 +1,27 @@
<?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\Event;
/**
* Allows to filter a Response object.
*
* You can call getResponse() to retrieve the current response. With
* setResponse() you can set a new response that will be returned to the
* browser.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @final since Symfony 4.4
*/
class ResponseEvent extends FilterResponseEvent
{
}

View File

@@ -0,0 +1,26 @@
<?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\Event;
/**
* Allows to execute logic after a response was sent.
*
* Since it's only triggered on master requests, the `getRequestType()` method
* will always return the value of `HttpKernelInterface::MASTER_REQUEST`.
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*
* @final since Symfony 4.4
*/
class TerminateEvent extends PostResponseEvent
{
}

View File

@@ -0,0 +1,27 @@
<?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\Event;
/**
* Allows to create a response for the return value of a controller.
*
* Call setResponse() to set the response that will be returned for the
* current request. The propagation of this event is stopped as soon as a
* response is set.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @final since Symfony 4.4
*/
class ViewEvent extends GetResponseForControllerResultEvent
{
}

View File

@@ -32,13 +32,15 @@ use Symfony\Component\HttpKernel\KernelEvents;
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
* @author Tobias Schultze <http://tobion.de>
*
* @internal since Symfony 4.3
*/
abstract class AbstractSessionListener implements EventSubscriberInterface
{
const NO_AUTO_CACHE_CONTROL_HEADER = 'Symfony-Session-NoAutoCacheControl';
public const NO_AUTO_CACHE_CONTROL_HEADER = 'Symfony-Session-NoAutoCacheControl';
protected $container;
private $sessionUsageStack = array();
private $sessionUsageStack = [];
public function __construct(ContainerInterface $container = null)
{
@@ -51,17 +53,13 @@ abstract class AbstractSessionListener implements EventSubscriberInterface
return;
}
$session = null;
$request = $event->getRequest();
if ($request->hasSession()) {
// no-op
} elseif (method_exists($request, 'setSessionFactory')) {
$request->setSessionFactory(function () { return $this->getSession(); });
} elseif ($session = $this->getSession()) {
$request->setSession($session);
if (!$request->hasSession()) {
$sess = null;
$request->setSessionFactory(function () use (&$sess) { return $sess ?? $sess = $this->getSession(); });
}
$session = $session ?? ($this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : null);
$session = $this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : null;
$this->sessionUsageStack[] = $session instanceof Session ? $session->getUsageIndex() : 0;
}
@@ -76,13 +74,14 @@ abstract class AbstractSessionListener implements EventSubscriberInterface
// 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()->getSession()) {
if (!$session = $this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : ($event->getRequest()->hasSession() ? $event->getRequest()->getSession() : null)) {
return;
}
if ($session instanceof Session ? $session->getUsageIndex() !== end($this->sessionUsageStack) : $session->isStarted()) {
if ($autoCacheControl) {
$response
->setExpires(new \DateTime())
->setPrivate()
->setMaxAge(0)
->headers->addCacheControlDirective('must-revalidate');
@@ -104,7 +103,7 @@ abstract class AbstractSessionListener implements EventSubscriberInterface
* the one above. But by saving the session before long-running things in the terminate event,
* we ensure the session is not blocked longer than needed.
* * When regenerating the session ID no locking is involved in PHPs session design. See
* https://bugs.php.net/bug.php?id=61470 for a discussion. So in this case, the session must
* https://bugs.php.net/61470 for a discussion. So in this case, the session must
* be saved anyway before sending the headers with the new session ID. Otherwise session
* data could get lost again for concurrent requests with the new ID. One result could be
* that you get logged out after just logging in.
@@ -131,12 +130,12 @@ abstract class AbstractSessionListener implements EventSubscriberInterface
public static function getSubscribedEvents()
{
return array(
KernelEvents::REQUEST => array('onKernelRequest', 128),
return [
KernelEvents::REQUEST => ['onKernelRequest', 128],
// low priority to come after regular response listeners, but higher than StreamedResponseListener
KernelEvents::RESPONSE => array('onKernelResponse', -1000),
KernelEvents::FINISH_REQUEST => array('onFinishRequest'),
);
KernelEvents::RESPONSE => ['onKernelResponse', -1000],
KernelEvents::FINISH_REQUEST => ['onFinishRequest'],
];
}
/**

View File

@@ -26,13 +26,15 @@ use Symfony\Component\HttpKernel\KernelEvents;
*
* @author Bulat Shakirzyanov <mallluhuct@gmail.com>
* @author Fabien Potencier <fabien@symfony.com>
*
* @internal since Symfony 4.3
*/
abstract class AbstractTestSessionListener implements EventSubscriberInterface
{
private $sessionId;
private $sessionOptions;
public function __construct(array $sessionOptions = array())
public function __construct(array $sessionOptions = [])
{
$this->sessionOptions = $sessionOptions;
}
@@ -44,8 +46,7 @@ abstract class AbstractTestSessionListener implements EventSubscriberInterface
}
// bootstrap the session
$session = $this->getSession();
if (!$session) {
if (!$session = $this->getSession()) {
return;
}
@@ -78,9 +79,9 @@ abstract class AbstractTestSessionListener implements EventSubscriberInterface
}
if ($session instanceof Session ? !$session->isEmpty() || (null !== $this->sessionId && $session->getId() !== $this->sessionId) : $wasStarted) {
$params = session_get_cookie_params() + array('samesite' => null);
$params = session_get_cookie_params() + ['samesite' => null];
foreach ($this->sessionOptions as $k => $v) {
if (0 === strpos($k, 'cookie_')) {
if (str_starts_with($k, 'cookie_')) {
$params[substr($k, 7)] = $v;
}
}
@@ -98,10 +99,10 @@ abstract class AbstractTestSessionListener implements EventSubscriberInterface
public static function getSubscribedEvents()
{
return array(
KernelEvents::REQUEST => array('onKernelRequest', 192),
KernelEvents::RESPONSE => array('onKernelResponse', -128),
);
return [
KernelEvents::REQUEST => ['onKernelRequest', 192],
KernelEvents::RESPONSE => ['onKernelResponse', -128],
];
}
/**

View File

@@ -19,6 +19,8 @@ use Symfony\Component\HttpKernel\KernelEvents;
* Adds configured formats to each request.
*
* @author Gildas Quemener <gildas.quemener@gmail.com>
*
* @final since Symfony 4.3
*/
class AddRequestFormatsListener implements EventSubscriberInterface
{
@@ -45,6 +47,6 @@ class AddRequestFormatsListener implements EventSubscriberInterface
*/
public static function getSubscribedEvents()
{
return array(KernelEvents::REQUEST => array('onKernelRequest', 1));
return [KernelEvents::REQUEST => ['onKernelRequest', 100]];
}
}

View File

@@ -15,10 +15,12 @@ use Psr\Log\LoggerInterface;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleEvent;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Debug\ErrorHandler;
use Symfony\Component\Debug\ExceptionHandler;
use Symfony\Component\Debug\ErrorHandler as LegacyErrorHandler;
use Symfony\Component\Debug\Exception\FatalThrowableError;
use Symfony\Component\ErrorHandler\ErrorHandler;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
use Symfony\Component\HttpKernel\Event\KernelEvent;
use Symfony\Component\HttpKernel\KernelEvents;
@@ -26,9 +28,12 @@ use Symfony\Component\HttpKernel\KernelEvents;
* Configures errors and exceptions handlers.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class DebugHandlersListener implements EventSubscriberInterface
{
private $earlyHandler;
private $exceptionHandler;
private $logger;
private $levels;
@@ -40,20 +45,23 @@ class DebugHandlersListener implements EventSubscriberInterface
private $hasTerminatedWithException;
/**
* @param callable|null $exceptionHandler A handler that will be called on Exception
* @param LoggerInterface|null $logger A PSR-3 logger
* @param array|int $levels An array map of E_* to LogLevel::* or an integer bit field of E_* constants
* @param int|null $throwAt Thrown errors in a bit field of E_* constants, or null to keep the current value
* @param bool $scream Enables/disables screaming mode, where even silenced errors are logged
* @param string|array $fileLinkFormat The format for links to source files
* @param bool $scope Enables/disables scoping mode
* @param callable|null $exceptionHandler A handler that must support \Throwable instances that will be called on Exception
* @param array|int $levels An array map of E_* to LogLevel::* or an integer bit field of E_* constants
* @param int|null $throwAt Thrown errors in a bit field of E_* constants, or null to keep the current value
* @param bool $scream Enables/disables screaming mode, where even silenced errors are logged
* @param string|FileLinkFormatter|null $fileLinkFormat The format for links to source files
* @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, $fileLinkFormat = null, bool $scope = true)
public function __construct(callable $exceptionHandler = null, LoggerInterface $logger = null, $levels = \E_ALL, ?int $throwAt = \E_ALL, bool $scream = true, $fileLinkFormat = null, bool $scope = true)
{
$handler = set_exception_handler('is_int');
$this->earlyHandler = \is_array($handler) ? $handler[0] : null;
restore_exception_handler();
$this->exceptionHandler = $exceptionHandler;
$this->logger = $logger;
$this->levels = null === $levels ? E_ALL : $levels;
$this->throwAt = \is_int($throwAt) ? $throwAt : (null === $throwAt ? null : ($throwAt ? E_ALL : null));
$this->levels = $levels ?? \E_ALL;
$this->throwAt = \is_int($throwAt) ? $throwAt : (null === $throwAt ? null : ($throwAt ? \E_ALL : null));
$this->scream = $scream;
$this->fileLinkFormat = $fileLinkFormat;
$this->scope = $scope;
@@ -64,17 +72,24 @@ class DebugHandlersListener implements EventSubscriberInterface
*/
public function configure(Event $event = null)
{
if ($event instanceof ConsoleEvent && !\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
return;
}
if (!$event instanceof KernelEvent ? !$this->firstCall : !$event->isMasterRequest()) {
return;
}
$this->firstCall = $this->hasTerminatedWithException = false;
$handler = set_exception_handler('var_dump');
$handler = set_exception_handler('is_int');
$handler = \is_array($handler) ? $handler[0] : null;
restore_exception_handler();
if (!$handler instanceof ErrorHandler && !$handler instanceof LegacyErrorHandler) {
$handler = $this->earlyHandler;
}
if ($this->logger || null !== $this->throwAt) {
if ($handler instanceof ErrorHandler) {
if ($handler instanceof ErrorHandler || $handler instanceof LegacyErrorHandler) {
if ($this->logger) {
$handler->setDefaultLogger($this->logger, $this->levels);
if (\is_array($this->levels)) {
@@ -89,7 +104,7 @@ class DebugHandlersListener implements EventSubscriberInterface
$handler->screamAt($levels);
}
if ($this->scope) {
$handler->scopeAt($levels & ~E_USER_DEPRECATED & ~E_DEPRECATED);
$handler->scopeAt($levels & ~\E_USER_DEPRECATED & ~\E_DEPRECATED);
} else {
$handler->scopeAt(0, true);
}
@@ -105,10 +120,11 @@ class DebugHandlersListener implements EventSubscriberInterface
if (method_exists($kernel = $event->getKernel(), 'terminateWithException')) {
$request = $event->getRequest();
$hasRun = &$this->hasTerminatedWithException;
$this->exceptionHandler = function (\Exception $e) use ($kernel, $request, &$hasRun) {
$this->exceptionHandler = static function (\Throwable $e) use ($kernel, $request, &$hasRun) {
if ($hasRun) {
throw $e;
}
$hasRun = true;
$kernel->terminateWithException($e, $request);
};
@@ -118,26 +134,22 @@ class DebugHandlersListener implements EventSubscriberInterface
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}
$this->exceptionHandler = function ($e) use ($app, $output) {
$app->renderException($e, $output);
$this->exceptionHandler = static function (\Throwable $e) use ($app, $output) {
if (method_exists($app, 'renderThrowable')) {
$app->renderThrowable($e, $output);
} else {
if (!$e instanceof \Exception) {
$e = new FatalThrowableError($e);
}
$app->renderException($e, $output);
}
};
}
}
if ($this->exceptionHandler) {
if ($handler instanceof ErrorHandler) {
$h = $handler->setExceptionHandler('var_dump');
if (\is_array($h) && $h[0] instanceof ExceptionHandler) {
$handler->setExceptionHandler($h);
$handler = $h[0];
} else {
$handler->setExceptionHandler($this->exceptionHandler);
}
}
if ($handler instanceof ExceptionHandler) {
$handler->setHandler($this->exceptionHandler);
if (null !== $this->fileLinkFormat) {
$handler->setFileLinkFormat($this->fileLinkFormat);
}
if ($handler instanceof ErrorHandler || $handler instanceof LegacyErrorHandler) {
$handler->setExceptionHandler($this->exceptionHandler);
}
$this->exceptionHandler = null;
}
@@ -145,10 +157,10 @@ class DebugHandlersListener implements EventSubscriberInterface
public static function getSubscribedEvents()
{
$events = array(KernelEvents::REQUEST => array('configure', 2048));
$events = [KernelEvents::REQUEST => ['configure', 2048]];
if ('cli' === \PHP_SAPI && \defined('Symfony\Component\Console\ConsoleEvents::COMMAND')) {
$events[ConsoleEvents::COMMAND] = array('configure', 2048);
if (\defined('Symfony\Component\Console\ConsoleEvents::COMMAND')) {
$events[ConsoleEvents::COMMAND] = ['configure', 2048];
}
return $events;

View File

@@ -0,0 +1,43 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* Ensures that the application is not indexed by search engines.
*
* @author Gary PEGEOT <garypegeot@gmail.com>
*/
class DisallowRobotsIndexingListener implements EventSubscriberInterface
{
private const HEADER_NAME = 'X-Robots-Tag';
public function onResponse(ResponseEvent $event): void
{
if (!$event->getResponse()->headers->has(static::HEADER_NAME)) {
$event->getResponse()->headers->set(static::HEADER_NAME, 'noindex');
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents()
{
return [
KernelEvents::RESPONSE => ['onResponse', -255],
];
}
}

View File

@@ -54,10 +54,10 @@ class DumpListener implements EventSubscriberInterface
public static function getSubscribedEvents()
{
if (!class_exists(ConsoleEvents::class)) {
return array();
return [];
}
// Register early to have a working dump() as early as possible
return array(ConsoleEvents::COMMAND => array('configure', 1024));
return [ConsoleEvents::COMMAND => ['configure', 1024]];
}
}

View File

@@ -0,0 +1,149 @@
<?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\Log\LoggerInterface;
use Symfony\Component\Debug\Exception\FlattenException as LegacyFlattenException;
use Symfony\Component\ErrorHandler\Exception\FlattenException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
class ErrorListener implements EventSubscriberInterface
{
protected $controller;
protected $logger;
protected $debug;
public function __construct($controller, LoggerInterface $logger = null, $debug = false)
{
$this->controller = $controller;
$this->logger = $logger;
$this->debug = $debug;
}
public function logKernelException(ExceptionEvent $event)
{
$e = FlattenException::createFromThrowable($event->getThrowable());
$this->logException($event->getThrowable(), sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', $e->getClass(), $e->getMessage(), $e->getFile(), $e->getLine()));
}
public function onKernelException(ExceptionEvent $event, string $eventName = null, EventDispatcherInterface $eventDispatcher = null)
{
if (null === $this->controller) {
return;
}
$exception = $event->getThrowable();
$request = $this->duplicateRequest($exception, $event->getRequest());
try {
$response = $event->getKernel()->handle($request, HttpKernelInterface::SUB_REQUEST, false);
} catch (\Exception $e) {
$f = FlattenException::createFromThrowable($e);
$this->logException($e, sprintf('Exception thrown when handling an exception (%s: %s at %s line %s)', $f->getClass(), $f->getMessage(), $e->getFile(), $e->getLine()));
$prev = $e;
do {
if ($exception === $wrapper = $prev) {
throw $e;
}
} while ($prev = $wrapper->getPrevious());
$prev = new \ReflectionProperty($wrapper instanceof \Exception ? \Exception::class : \Error::class, 'previous');
$prev->setAccessible(true);
$prev->setValue($wrapper, $exception);
throw $e;
}
$event->setResponse($response);
if ($this->debug && $eventDispatcher instanceof EventDispatcherInterface) {
$cspRemovalListener = function ($event) use (&$cspRemovalListener, $eventDispatcher) {
$event->getResponse()->headers->remove('Content-Security-Policy');
$eventDispatcher->removeListener(KernelEvents::RESPONSE, $cspRemovalListener);
};
$eventDispatcher->addListener(KernelEvents::RESPONSE, $cspRemovalListener, -128);
}
}
public function onControllerArguments(ControllerArgumentsEvent $event)
{
$e = $event->getRequest()->attributes->get('exception');
if (!$e instanceof \Throwable || false === $k = array_search($e, $event->getArguments(), true)) {
return;
}
$r = new \ReflectionFunction(\Closure::fromCallable($event->getController()));
$r = $r->getParameters()[$k] ?? null;
if ($r && (!($r = $r->getType()) instanceof \ReflectionNamedType || \in_array($r->getName(), [FlattenException::class, LegacyFlattenException::class], true))) {
$arguments = $event->getArguments();
$arguments[$k] = FlattenException::createFromThrowable($e);
$event->setArguments($arguments);
}
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::CONTROLLER_ARGUMENTS => 'onControllerArguments',
KernelEvents::EXCEPTION => [
['logKernelException', 0],
['onKernelException', -128],
],
];
}
/**
* Logs an exception.
*/
protected function logException(\Throwable $exception, string $message): void
{
if (null !== $this->logger) {
if (!$exception instanceof HttpExceptionInterface || $exception->getStatusCode() >= 500) {
$this->logger->critical($message, ['exception' => $exception]);
} else {
$this->logger->error($message, ['exception' => $exception]);
}
}
}
/**
* Clones the request for the exception.
*/
protected function duplicateRequest(\Throwable $exception, Request $request): Request
{
$attributes = [
'_controller' => $this->controller,
'exception' => $exception,
'logger' => $this->logger instanceof DebugLoggerInterface ? $this->logger : null,
];
$request = $request->duplicate(null, null, $attributes);
$request->setMethod('GET');
return $request;
}
}

View File

@@ -12,45 +12,37 @@
namespace Symfony\Component\HttpKernel\EventListener;
use Psr\Log\LoggerInterface;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\Debug\ExceptionHandler;
use Symfony\Component\ErrorHandler\Exception\FlattenException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "ErrorListener" instead.', ExceptionListener::class), \E_USER_DEPRECATED);
/**
* ExceptionListener.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since Symfony 4.4, use ErrorListener instead
*/
class ExceptionListener implements EventSubscriberInterface
{
protected $controller;
protected $logger;
protected $debug;
private $charset;
private $fileLinkFormat;
private $isTerminating = false;
public function __construct($controller, LoggerInterface $logger = null, $debug = false, string $charset = null, $fileLinkFormat = null)
public function __construct($controller, LoggerInterface $logger = null, $debug = false)
{
$this->controller = $controller;
$this->logger = $logger;
$this->debug = $debug;
$this->charset = $charset;
$this->fileLinkFormat = $fileLinkFormat;
}
public function logKernelException(GetResponseForExceptionEvent $event)
{
$e = FlattenException::create($event->getException());
$e = FlattenException::createFromThrowable($event->getException());
$this->logException($event->getException(), sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', $e->getClass(), $e->getMessage(), $e->getFile(), $e->getLine()));
}
@@ -58,16 +50,9 @@ class ExceptionListener implements EventSubscriberInterface
public function onKernelException(GetResponseForExceptionEvent $event)
{
if (null === $this->controller) {
if (!$event->isMasterRequest()) {
return;
}
if (!$this->isTerminating) {
$this->isTerminating = true;
return;
}
$this->isTerminating = false;
return;
}
$exception = $event->getException();
$request = $this->duplicateRequest($exception, $event->getRequest());
$eventDispatcher = \func_num_args() > 2 ? func_get_arg(2) : null;
@@ -75,17 +60,16 @@ class ExceptionListener implements EventSubscriberInterface
try {
$response = $event->getKernel()->handle($request, HttpKernelInterface::SUB_REQUEST, false);
} catch (\Exception $e) {
$f = FlattenException::create($e);
$f = FlattenException::createFromThrowable($e);
$this->logException($e, sprintf('Exception thrown when handling an exception (%s: %s at %s line %s)', $f->getClass(), $f->getMessage(), $e->getFile(), $e->getLine()));
$wrapper = $e;
while ($prev = $wrapper->getPrevious()) {
$prev = $e;
do {
if ($exception === $wrapper = $prev) {
throw $e;
}
}
} while ($prev = $wrapper->getPrevious());
$prev = new \ReflectionProperty($wrapper instanceof \Exception ? \Exception::class : \Error::class, 'previous');
$prev->setAccessible(true);
@@ -97,7 +81,7 @@ class ExceptionListener implements EventSubscriberInterface
$event->setResponse($response);
if ($this->debug && $eventDispatcher instanceof EventDispatcherInterface) {
$cspRemovalListener = function (FilterResponseEvent $event) use (&$cspRemovalListener, $eventDispatcher) {
$cspRemovalListener = function ($event) use (&$cspRemovalListener, $eventDispatcher) {
$event->getResponse()->headers->remove('Content-Security-Policy');
$eventDispatcher->removeListener(KernelEvents::RESPONSE, $cspRemovalListener);
};
@@ -105,19 +89,14 @@ class ExceptionListener implements EventSubscriberInterface
}
}
public function reset()
{
$this->isTerminating = false;
}
public static function getSubscribedEvents()
{
return array(
KernelEvents::EXCEPTION => array(
array('logKernelException', 0),
array('onKernelException', -128),
),
);
return [
KernelEvents::EXCEPTION => [
['logKernelException', 0],
['onKernelException', -128],
],
];
}
/**
@@ -130,9 +109,9 @@ class ExceptionListener implements EventSubscriberInterface
{
if (null !== $this->logger) {
if (!$exception instanceof HttpExceptionInterface || $exception->getStatusCode() >= 500) {
$this->logger->critical($message, array('exception' => $exception));
$this->logger->critical($message, ['exception' => $exception]);
} else {
$this->logger->error($message, array('exception' => $exception));
$this->logger->error($message, ['exception' => $exception]);
}
}
}
@@ -140,22 +119,15 @@ class ExceptionListener implements EventSubscriberInterface
/**
* Clones the request for the exception.
*
* @param \Exception $exception The thrown exception
* @param Request $request The original request
*
* @return Request The cloned request
*/
protected function duplicateRequest(\Exception $exception, Request $request)
{
$attributes = array(
'exception' => $exception = FlattenException::create($exception),
'_controller' => $this->controller ?: function () use ($exception) {
$handler = new ExceptionHandler($this->debug, $this->charset, $this->fileLinkFormat);
return new Response($handler->getHtml($exception), $exception->getStatusCode(), $exception->getHeaders());
},
$attributes = [
'_controller' => $this->controller,
'exception' => FlattenException::createFromThrowable($exception),
'logger' => $this->logger instanceof DebugLoggerInterface ? $this->logger : null,
);
];
$request = $request->duplicate(null, null, $attributes);
$request->setMethod('GET');

View File

@@ -24,10 +24,12 @@ use Symfony\Component\HttpKernel\UriSigner;
* All URL paths starting with /_fragment are handled as
* content fragments by this listener.
*
* If throws an AccessDeniedHttpException exception if the request
* Throws an AccessDeniedHttpException exception if the request
* is not signed or if it is not an internal sub-request.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.3
*/
class FragmentListener implements EventSubscriberInterface
{
@@ -35,8 +37,7 @@ class FragmentListener implements EventSubscriberInterface
private $fragmentPath;
/**
* @param UriSigner $signer A UriSigner instance
* @param string $fragmentPath The path that triggers this listener
* @param string $fragmentPath The path that triggers this listener
*/
public function __construct(UriSigner $signer, string $fragmentPath = '/_fragment')
{
@@ -70,14 +71,14 @@ class FragmentListener implements EventSubscriberInterface
parse_str($request->query->get('_path', ''), $attributes);
$request->attributes->add($attributes);
$request->attributes->set('_route_params', array_replace($request->attributes->get('_route_params', array()), $attributes));
$request->attributes->set('_route_params', array_replace($request->attributes->get('_route_params', []), $attributes));
$request->query->remove('_path');
}
protected function validateRequest(Request $request)
{
// is the Request safe?
if (!$request->isMethodSafe(false)) {
if (!$request->isMethodSafe()) {
throw new AccessDeniedHttpException();
}
@@ -92,8 +93,8 @@ class FragmentListener implements EventSubscriberInterface
public static function getSubscribedEvents()
{
return array(
KernelEvents::REQUEST => array(array('onKernelRequest', 48)),
);
return [
KernelEvents::REQUEST => [['onKernelRequest', 48]],
];
}
}

View File

@@ -0,0 +1,77 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Contracts\Translation\LocaleAwareInterface;
/**
* Pass the current locale to the provided services.
*
* @author Pierre Bobiet <pierrebobiet@gmail.com>
*/
class LocaleAwareListener implements EventSubscriberInterface
{
private $localeAwareServices;
private $requestStack;
/**
* @param LocaleAwareInterface[] $localeAwareServices
*/
public function __construct(iterable $localeAwareServices, RequestStack $requestStack)
{
$this->localeAwareServices = $localeAwareServices;
$this->requestStack = $requestStack;
}
public function onKernelRequest(RequestEvent $event): void
{
$this->setLocale($event->getRequest()->getLocale(), $event->getRequest()->getDefaultLocale());
}
public function onKernelFinishRequest(FinishRequestEvent $event): void
{
if (null === $parentRequest = $this->requestStack->getParentRequest()) {
foreach ($this->localeAwareServices as $service) {
$service->setLocale($event->getRequest()->getDefaultLocale());
}
return;
}
$this->setLocale($parentRequest->getLocale(), $parentRequest->getDefaultLocale());
}
public static function getSubscribedEvents()
{
return [
// must be registered after the Locale listener
KernelEvents::REQUEST => [['onKernelRequest', 15]],
KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', -15]],
];
}
private function setLocale(string $locale, string $defaultLocale): void
{
foreach ($this->localeAwareServices as $service) {
try {
$service->setLocale($locale);
} catch (\InvalidArgumentException $e) {
$service->setLocale($defaultLocale);
}
}
}
}

View File

@@ -16,6 +16,7 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\KernelEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\RequestContextAwareInterface;
@@ -23,6 +24,8 @@ use Symfony\Component\Routing\RequestContextAwareInterface;
* Initializes the locale based on the current request.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.3
*/
class LocaleListener implements EventSubscriberInterface
{
@@ -30,11 +33,6 @@ class LocaleListener implements EventSubscriberInterface
private $defaultLocale;
private $requestStack;
/**
* @param RequestStack $requestStack A RequestStack instance
* @param string $defaultLocale The default locale
* @param RequestContextAwareInterface|null $router The router
*/
public function __construct(RequestStack $requestStack, string $defaultLocale = 'en', RequestContextAwareInterface $router = null)
{
$this->defaultLocale = $defaultLocale;
@@ -42,10 +40,14 @@ class LocaleListener implements EventSubscriberInterface
$this->router = $router;
}
public function setDefaultLocale(KernelEvent $event)
{
$event->getRequest()->setDefaultLocale($this->defaultLocale);
}
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
$request->setDefaultLocale($this->defaultLocale);
$this->setLocale($request);
$this->setRouterContext($request);
@@ -74,10 +76,13 @@ class LocaleListener implements EventSubscriberInterface
public static function getSubscribedEvents()
{
return array(
// must be registered after the Router to have access to the _locale
KernelEvents::REQUEST => array(array('onKernelRequest', 16)),
KernelEvents::FINISH_REQUEST => array(array('onKernelFinishRequest', 0)),
);
return [
KernelEvents::REQUEST => [
['setDefaultLocale', 100],
// must be registered after the Router to have access to the _locale
['onKernelRequest', 16],
],
KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', 0]],
];
}
}

View File

@@ -12,8 +12,10 @@
namespace Symfony\Component\HttpKernel\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Event\PostResponseEvent;
@@ -24,6 +26,8 @@ use Symfony\Component\HttpKernel\Profiler\Profiler;
* ProfilerListener collects data for the current request by listening to the kernel events.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.3
*/
class ProfilerListener implements EventSubscriberInterface
{
@@ -37,11 +41,8 @@ class ProfilerListener implements EventSubscriberInterface
protected $parents;
/**
* @param Profiler $profiler A Profiler instance
* @param RequestStack $requestStack A RequestStack instance
* @param RequestMatcherInterface|null $matcher A RequestMatcher instance
* @param bool $onlyException True if the profiler only collects data when an exception occurs, false otherwise
* @param bool $onlyMasterRequests True if the profiler only collects data when the request is a master request, false otherwise
* @param bool $onlyException True if the profiler only collects data when an exception occurs, false otherwise
* @param bool $onlyMasterRequests True if the profiler only collects data when the request is a master request, false otherwise
*/
public function __construct(Profiler $profiler, RequestStack $requestStack, RequestMatcherInterface $matcher = null, bool $onlyException = false, bool $onlyMasterRequests = false)
{
@@ -63,7 +64,7 @@ class ProfilerListener implements EventSubscriberInterface
return;
}
$this->exception = $event->getException();
$this->exception = $event->getThrowable();
}
/**
@@ -88,8 +89,21 @@ class ProfilerListener implements EventSubscriberInterface
return;
}
if (!$profile = $this->profiler->collect($request, $event->getResponse(), $exception)) {
return;
$session = method_exists(Request::class, 'getPreferredFormat') && $request->hasPreviousSession() && $request->hasSession() ? $request->getSession() : null;
if ($session instanceof Session) {
$usageIndexValue = $usageIndexReference = &$session->getUsageIndex();
$usageIndexReference = \PHP_INT_MIN;
}
try {
if (!$profile = $this->profiler->collect($request, $event->getResponse(), $exception)) {
return;
}
} finally {
if ($session instanceof Session) {
$usageIndexReference = $usageIndexValue;
}
}
$this->profiles[$request] = $profile;
@@ -119,10 +133,10 @@ class ProfilerListener implements EventSubscriberInterface
public static function getSubscribedEvents()
{
return array(
KernelEvents::RESPONSE => array('onKernelResponse', -100),
KernelEvents::EXCEPTION => array('onKernelException', 0),
KernelEvents::TERMINATE => array('onKernelTerminate', -1024),
);
return [
KernelEvents::RESPONSE => ['onKernelResponse', -100],
KernelEvents::EXCEPTION => ['onKernelException', 0],
KernelEvents::TERMINATE => ['onKernelTerminate', -1024],
];
}
}

View File

@@ -19,6 +19,8 @@ use Symfony\Component\HttpKernel\KernelEvents;
* ResponseListener fixes the Response headers based on the Request.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.3
*/
class ResponseListener implements EventSubscriberInterface
{
@@ -49,8 +51,8 @@ class ResponseListener implements EventSubscriberInterface
public static function getSubscribedEvents()
{
return array(
return [
KernelEvents::RESPONSE => 'onKernelResponse',
);
];
}
}

View File

@@ -37,6 +37,8 @@ use Symfony\Component\Routing\RequestContextAwareInterface;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Yonel Ceruto <yonelceruto@gmail.com>
*
* @final since Symfony 4.3
*/
class RouterListener implements EventSubscriberInterface
{
@@ -48,12 +50,9 @@ class RouterListener implements EventSubscriberInterface
private $debug;
/**
* @param UrlMatcherInterface|RequestMatcherInterface $matcher The Url or Request matcher
* @param RequestStack $requestStack A RequestStack instance
* @param RequestContext|null $context The RequestContext (can be null when $matcher implements RequestContextAwareInterface)
* @param LoggerInterface|null $logger The logger
* @param UrlMatcherInterface|RequestMatcherInterface $matcher The Url or Request matcher
* @param RequestContext|null $context The RequestContext (can be null when $matcher implements RequestContextAwareInterface)
* @param string $projectDir
* @param bool $debug
*
* @throws \InvalidArgumentException
*/
@@ -89,8 +88,6 @@ 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.
*
* @param FinishRequestEvent $event
*/
public function onKernelFinishRequest(FinishRequestEvent $event)
{
@@ -118,12 +115,12 @@ class RouterListener implements EventSubscriberInterface
}
if (null !== $this->logger) {
$this->logger->info('Matched route "{route}".', array(
'route' => isset($parameters['_route']) ? $parameters['_route'] : 'n/a',
$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);
@@ -146,7 +143,7 @@ class RouterListener implements EventSubscriberInterface
public function onKernelException(GetResponseForExceptionEvent $event)
{
if (!$this->debug || !($e = $event->getException()) instanceof NotFoundHttpException) {
if (!$this->debug || !($e = $event->getThrowable()) instanceof NotFoundHttpException) {
return;
}
@@ -157,21 +154,21 @@ class RouterListener implements EventSubscriberInterface
public static function getSubscribedEvents()
{
return array(
KernelEvents::REQUEST => array(array('onKernelRequest', 32)),
KernelEvents::FINISH_REQUEST => array(array('onKernelFinishRequest', 0)),
KernelEvents::EXCEPTION => array('onKernelException', -64),
);
return [
KernelEvents::REQUEST => [['onKernelRequest', 32]],
KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', 0]],
KernelEvents::EXCEPTION => ['onKernelException', -64],
];
}
private function createWelcomeResponse()
private function createWelcomeResponse(): Response
{
$version = Kernel::VERSION;
$baseDir = realpath($this->projectDir).\DIRECTORY_SEPARATOR;
$projectDir = realpath((string) $this->projectDir).\DIRECTORY_SEPARATOR;
$docVersion = substr(Kernel::VERSION, 0, 3);
ob_start();
include __DIR__.'/../Resources/welcome.html.php';
include \dirname(__DIR__).'/Resources/welcome.html.php';
return new Response(ob_get_clean(), Response::HTTP_NOT_FOUND);
}

View File

@@ -11,7 +11,7 @@
namespace Symfony\Component\HttpKernel\EventListener;
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.1, use AbstractSessionListener instead.', SaveSessionListener::class), E_USER_DEPRECATED);
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.1, use AbstractSessionListener instead.', SaveSessionListener::class), \E_USER_DEPRECATED);
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
@@ -30,17 +30,17 @@ class SaveSessionListener implements EventSubscriberInterface
return;
}
$session = $event->getRequest()->getSession();
if ($session && $session->isStarted()) {
$request = $event->getRequest();
if ($request->hasSession() && ($session = $request->getSession())->isStarted()) {
$session->save();
}
}
public static function getSubscribedEvents()
{
return array(
return [
// low priority but higher than StreamedResponseListener
KernelEvents::RESPONSE => array(array('onKernelResponse', -1000)),
);
KernelEvents::RESPONSE => [['onKernelResponse', -1000]],
];
}
}

View File

@@ -12,7 +12,9 @@
namespace Symfony\Component\HttpKernel\EventListener;
use Psr\Container\ContainerInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
/**
* Sets the session in the request.
@@ -32,17 +34,27 @@ class SessionListener extends AbstractSessionListener
$this->container = $container;
}
protected function getSession()
public function onKernelRequest(GetResponseEvent $event)
{
if (!$this->container->has('session')) {
parent::onKernelRequest($event);
if (!$event->isMasterRequest() || !$this->container->has('session')) {
return;
}
if ($this->container->has('session_storage')
&& ($storage = $this->container->get('session_storage')) instanceof NativeSessionStorage
&& $this->container->get('request_stack')->getMasterRequest()->isSecure()
&& ($masterRequest = $this->container->get('request_stack')->getMasterRequest())
&& $masterRequest->isSecure()
) {
$storage->setOptions(array('cookie_secure' => true));
$storage->setOptions(['cookie_secure' => true]);
}
}
protected function getSession(): ?SessionInterface
{
if (!$this->container->has('session')) {
return null;
}
return $this->container->get('session');

View File

@@ -21,6 +21,8 @@ use Symfony\Component\HttpKernel\KernelEvents;
* to the client.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.3
*/
class StreamedResponseListener implements EventSubscriberInterface
{
@@ -42,8 +44,8 @@ class StreamedResponseListener implements EventSubscriberInterface
public static function getSubscribedEvents()
{
return array(
KernelEvents::RESPONSE => array('onKernelResponse', -1024),
);
return [
KernelEvents::RESPONSE => ['onKernelResponse', -1024],
];
}
}

View File

@@ -21,6 +21,8 @@ use Symfony\Component\HttpKernel\KernelEvents;
* SurrogateListener adds a Surrogate-Control HTTP header when the Response needs to be parsed for Surrogates.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.3
*/
class SurrogateListener implements EventSubscriberInterface
{
@@ -58,8 +60,8 @@ class SurrogateListener implements EventSubscriberInterface
public static function getSubscribedEvents()
{
return array(
return [
KernelEvents::RESPONSE => 'onKernelResponse',
);
];
}
}

View File

@@ -12,6 +12,7 @@
namespace Symfony\Component\HttpKernel\EventListener;
use Psr\Container\ContainerInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
/**
* Sets the session in the request.
@@ -24,16 +25,16 @@ class TestSessionListener extends AbstractTestSessionListener
{
private $container;
public function __construct(ContainerInterface $container, array $sessionOptions = array())
public function __construct(ContainerInterface $container, array $sessionOptions = [])
{
$this->container = $container;
parent::__construct($sessionOptions);
}
protected function getSession()
protected function getSession(): ?SessionInterface
{
if (!$this->container->has('session')) {
return;
return null;
}
return $this->container->get('session');

View File

@@ -11,19 +11,23 @@
namespace Symfony\Component\HttpKernel\EventListener;
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3 and will be removed in 5.0, use LocaleAwareListener instead.', TranslatorListener::class), \E_USER_DEPRECATED);
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Contracts\Translation\LocaleAwareInterface;
/**
* Synchronizes the locale between the request and the translator.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since Symfony 4.3, use LocaleAwareListener instead
*/
class TranslatorListener implements EventSubscriberInterface
{
@@ -31,12 +35,12 @@ class TranslatorListener implements EventSubscriberInterface
private $requestStack;
/**
* @param TranslatorInterface $translator
* @param LocaleAwareInterface $translator
*/
public function __construct($translator, RequestStack $requestStack)
{
if (!$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) {
throw new \TypeError(sprintf('Argument 1 passed to %s() must be an instance of %s, %s given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
if (!$translator instanceof TranslatorInterface && !$translator instanceof LocaleAwareInterface) {
throw new \TypeError(sprintf('Argument 1 passed to "%s()" must be an instance of "%s", "%s" given.', __METHOD__, LocaleAwareInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
}
$this->translator = $translator;
$this->requestStack = $requestStack;
@@ -58,11 +62,11 @@ class TranslatorListener implements EventSubscriberInterface
public static function getSubscribedEvents()
{
return array(
return [
// must be registered after the Locale listener
KernelEvents::REQUEST => array(array('onKernelRequest', 10)),
KernelEvents::FINISH_REQUEST => array(array('onKernelFinishRequest', 0)),
);
KernelEvents::REQUEST => [['onKernelRequest', 10]],
KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', 0]],
];
}
private function setLocale(Request $request)

View File

@@ -19,6 +19,8 @@ use Symfony\Component\HttpKernel\KernelEvents;
* Validates Requests.
*
* @author Magnus Nordlander <magnus@fervo.se>
*
* @final since Symfony 4.3
*/
class ValidateRequestListener implements EventSubscriberInterface
{
@@ -44,10 +46,10 @@ class ValidateRequestListener implements EventSubscriberInterface
*/
public static function getSubscribedEvents()
{
return array(
KernelEvents::REQUEST => array(
array('onKernelRequest', 256),
),
);
return [
KernelEvents::REQUEST => [
['onKernelRequest', 256],
],
];
}
}

View File

@@ -18,12 +18,11 @@ namespace Symfony\Component\HttpKernel\Exception;
class AccessDeniedHttpException extends HttpException
{
/**
* @param string $message The internal exception message
* @param \Exception $previous The previous exception
* @param int $code The internal exception code
* @param array $headers
* @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 = null, \Exception $previous = null, int $code = 0, array $headers = array())
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
parent::__construct(403, $message, $previous, $headers, $code);
}

View File

@@ -17,12 +17,11 @@ namespace Symfony\Component\HttpKernel\Exception;
class BadRequestHttpException extends HttpException
{
/**
* @param string $message The internal exception message
* @param \Exception $previous The previous exception
* @param int $code The internal exception code
* @param array $headers
* @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 = null, \Exception $previous = null, int $code = 0, array $headers = array())
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
parent::__construct(400, $message, $previous, $headers, $code);
}

View File

@@ -17,12 +17,11 @@ namespace Symfony\Component\HttpKernel\Exception;
class ConflictHttpException extends HttpException
{
/**
* @param string $message The internal exception message
* @param \Exception $previous The previous exception
* @param int $code The internal exception code
* @param array $headers
* @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 = null, \Exception $previous = null, int $code = 0, array $headers = array())
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
parent::__construct(409, $message, $previous, $headers, $code);
}

View File

@@ -28,17 +28,17 @@ class ControllerDoesNotReturnResponseException extends \LogicException
$this->line = $controllerDefinition['line'];
$r = new \ReflectionProperty(\Exception::class, 'trace');
$r->setAccessible(true);
$r->setValue($this, array_merge(array(
array(
$r->setValue($this, array_merge([
[
'line' => $line,
'file' => $file,
),
), $this->getTrace()));
],
], $this->getTrace()));
}
private function parseControllerDefinition(callable $controller): ?array
{
if (\is_string($controller) && false !== strpos($controller, '::')) {
if (\is_string($controller) && str_contains($controller, '::')) {
$controller = explode('::', $controller);
}
@@ -46,10 +46,10 @@ class ControllerDoesNotReturnResponseException extends \LogicException
try {
$r = new \ReflectionMethod($controller[0], $controller[1]);
return array(
return [
'file' => $r->getFileName(),
'line' => $r->getEndLine(),
);
];
} catch (\ReflectionException $e) {
return null;
}
@@ -58,19 +58,25 @@ class ControllerDoesNotReturnResponseException extends \LogicException
if ($controller instanceof \Closure) {
$r = new \ReflectionFunction($controller);
return array(
return [
'file' => $r->getFileName(),
'line' => $r->getEndLine(),
);
];
}
if (\is_object($controller)) {
$r = new \ReflectionClass($controller);
return array(
try {
$line = $r->getMethod('__invoke')->getEndLine();
} catch (\ReflectionException $e) {
$line = $r->getEndLine();
}
return [
'file' => $r->getFileName(),
'line' => $r->getEndLine(),
);
'line' => $line,
];
}
return null;

View File

@@ -17,12 +17,11 @@ namespace Symfony\Component\HttpKernel\Exception;
class GoneHttpException extends HttpException
{
/**
* @param string $message The internal exception message
* @param \Exception $previous The previous exception
* @param int $code The internal exception code
* @param array $headers
* @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 = null, \Exception $previous = null, int $code = 0, array $headers = array())
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
parent::__construct(410, $message, $previous, $headers, $code);
}

View File

@@ -21,7 +21,7 @@ class HttpException extends \RuntimeException implements HttpExceptionInterface
private $statusCode;
private $headers;
public function __construct(int $statusCode, string $message = null, \Exception $previous = null, array $headers = array(), ?int $code = 0)
public function __construct(int $statusCode, ?string $message = '', \Throwable $previous = null, array $headers = [], ?int $code = 0)
{
$this->statusCode = $statusCode;
$this->headers = $headers;

View File

@@ -16,7 +16,7 @@ namespace Symfony\Component\HttpKernel\Exception;
*
* @author Kris Wallsmith <kris@symfony.com>
*/
interface HttpExceptionInterface
interface HttpExceptionInterface extends \Throwable
{
/**
* Returns the status code.

View File

@@ -17,12 +17,11 @@ namespace Symfony\Component\HttpKernel\Exception;
class LengthRequiredHttpException extends HttpException
{
/**
* @param string $message The internal exception message
* @param \Exception $previous The previous exception
* @param int $code The internal exception code
* @param array $headers
* @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 = null, \Exception $previous = null, int $code = 0, array $headers = array())
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
parent::__construct(411, $message, $previous, $headers, $code);
}

View File

@@ -17,13 +17,12 @@ namespace Symfony\Component\HttpKernel\Exception;
class MethodNotAllowedHttpException extends HttpException
{
/**
* @param array $allow An array of allowed methods
* @param string $message The internal exception message
* @param \Exception $previous The previous exception
* @param int $code The internal exception code
* @param array $headers
* @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
*/
public function __construct(array $allow, string $message = null, \Exception $previous = null, ?int $code = 0, array $headers = array())
public function __construct(array $allow, ?string $message = '', \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
$headers['Allow'] = strtoupper(implode(', ', $allow));

View File

@@ -17,12 +17,11 @@ namespace Symfony\Component\HttpKernel\Exception;
class NotAcceptableHttpException extends HttpException
{
/**
* @param string $message The internal exception message
* @param \Exception $previous The previous exception
* @param int $code The internal exception code
* @param array $headers
* @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 = null, \Exception $previous = null, int $code = 0, array $headers = array())
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
parent::__construct(406, $message, $previous, $headers, $code);
}

View File

@@ -17,12 +17,11 @@ namespace Symfony\Component\HttpKernel\Exception;
class NotFoundHttpException extends HttpException
{
/**
* @param string $message The internal exception message
* @param \Exception $previous The previous exception
* @param int $code The internal exception code
* @param array $headers
* @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 = null, \Exception $previous = null, int $code = 0, array $headers = array())
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
parent::__construct(404, $message, $previous, $headers, $code);
}

View File

@@ -17,12 +17,11 @@ namespace Symfony\Component\HttpKernel\Exception;
class PreconditionFailedHttpException extends HttpException
{
/**
* @param string $message The internal exception message
* @param \Exception $previous The previous exception
* @param int $code The internal exception code
* @param array $headers
* @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 = null, \Exception $previous = null, int $code = 0, array $headers = array())
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
parent::__construct(412, $message, $previous, $headers, $code);
}

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