upgraded dependencies

This commit is contained in:
RafficMohammed
2023-01-08 01:59:16 +05:30
parent 51056e3aad
commit f9ae387337
6895 changed files with 133617 additions and 178680 deletions

View File

@@ -0,0 +1,23 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Attribute;
trigger_deprecation('symfony/http-kernel', '5.3', 'The "%s" interface is deprecated.', ArgumentInterface::class);
/**
* Marker interface for controller argument attributes.
*
* @deprecated since Symfony 5.3
*/
interface ArgumentInterface
{
}

View File

@@ -0,0 +1,23 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Attribute;
/**
* Service tag to autoconfigure controllers.
*/
#[\Attribute(\Attribute::TARGET_CLASS)]
class AsController
{
public function __construct()
{
}
}

View File

@@ -58,7 +58,7 @@ abstract class Bundle implements BundleInterface
/**
* Returns the bundle's container extension.
*
* @return ExtensionInterface|null The container extension
* @return ExtensionInterface|null
*
* @throws \LogicException
*/
@@ -69,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_debug_type($extension)));
}
// check naming convention

View File

@@ -42,21 +42,21 @@ interface BundleInterface extends ContainerAwareInterface
/**
* Returns the container extension that should be implicitly loaded.
*
* @return ExtensionInterface|null The default extension or null if there is none
* @return ExtensionInterface|null
*/
public function getContainerExtension();
/**
* Returns the bundle name (the class short name).
*
* @return string The Bundle name
* @return string
*/
public function getName();
/**
* Gets the Bundle namespace.
*
* @return string The Bundle namespace
* @return string
*/
public function getNamespace();
@@ -65,7 +65,7 @@ interface BundleInterface extends ContainerAwareInterface
*
* The path should always be returned as a Unix path (with /).
*
* @return string The Bundle absolute path
* @return string
*/
public function getPath();
}

View File

@@ -1,6 +1,82 @@
CHANGELOG
=========
5.4
---
* Add the ability to enable the profiler using a request query parameter, body parameter or attribute
* Deprecate `AbstractTestSessionListener` and `TestSessionListener`, use `AbstractSessionListener` and `SessionListener` instead
* Deprecate the `fileLinkFormat` parameter of `DebugHandlersListener`
* Add support for configuring log level, and status code by exception class
* Allow ignoring "kernel.reset" methods that don't exist with "on_invalid" attribute
5.3
---
* Deprecate `ArgumentInterface`
* Add `ArgumentMetadata::getAttributes()`
* Deprecate `ArgumentMetadata::getAttribute()`, use `getAttributes()` instead
* Mark the class `Symfony\Component\HttpKernel\EventListener\DebugHandlersListener` as internal
* Deprecate returning a `ContainerBuilder` from `KernelInterface::registerContainerConfiguration()`
* Deprecate `HttpKernelInterface::MASTER_REQUEST` and add `HttpKernelInterface::MAIN_REQUEST` as replacement
* Deprecate `KernelEvent::isMasterRequest()` and add `isMainRequest()` as replacement
* Add `#[AsController]` attribute for declaring standalone controllers on PHP 8
* Add `FragmentUriGeneratorInterface` and `FragmentUriGenerator` to generate the URI of a fragment
5.2.0
-----
* added session usage
* made the public `http_cache` service handle requests when available
* allowed enabling trusted hosts and proxies using new `kernel.trusted_hosts`,
`kernel.trusted_proxies` and `kernel.trusted_headers` parameters
* content of request parameter `_password` is now also hidden
in the request profiler raw content section
* Allowed adding attributes on controller arguments that will be passed to argument resolvers.
* kernels implementing the `ExtensionInterface` will now be auto-registered to the container
* added parameter `kernel.runtime_environment`, defined as `%env(default:kernel.environment:APP_RUNTIME_ENV)%`
* do not set a default `Accept` HTTP header when using `HttpKernelBrowser`
5.1.0
-----
* allowed to use a specific logger channel for deprecations
* made `WarmableInterface::warmUp()` return a list of classes or files to preload on PHP 7.4+;
not returning an array is deprecated
* made kernels implementing `WarmableInterface` be part of the cache warmup stage
* deprecated support for `service:action` syntax to reference controllers, use `serviceOrFqcn::method` instead
* allowed using public aliases to reference controllers
* added session usage reporting when the `_stateless` attribute of the request is set to `true`
* added `AbstractSessionListener::onSessionUsage()` to report when the session is used while a request is stateless
5.0.0
-----
* removed support for getting the container from a non-booted kernel
* removed the first and second constructor argument of `ConfigDataCollector`
* removed `ConfigDataCollector::getApplicationName()`
* removed `ConfigDataCollector::getApplicationVersion()`
* removed support for `Symfony\Component\Templating\EngineInterface` in `HIncludeFragmentRenderer`, use a `Twig\Environment` only
* removed `TranslatorListener` in favor of `LocaleAwareListener`
* removed `getRootDir()` and `getName()` from `Kernel` and `KernelInterface`
* removed `FilterControllerArgumentsEvent`, use `ControllerArgumentsEvent` instead
* removed `FilterControllerEvent`, use `ControllerEvent` instead
* removed `FilterResponseEvent`, use `ResponseEvent` instead
* removed `GetResponseEvent`, use `RequestEvent` instead
* removed `GetResponseForControllerResultEvent`, use `ViewEvent` instead
* removed `GetResponseForExceptionEvent`, use `ExceptionEvent` instead
* removed `PostResponseEvent`, use `TerminateEvent` instead
* removed `SaveSessionListener` in favor of `AbstractSessionListener`
* removed `Client`, use `HttpKernelBrowser` instead
* added method `getProjectDir()` to `KernelInterface`
* removed methods `serialize` and `unserialize` from `DataCollector`, store the serialized state in the data property instead
* made `ProfilerStorageInterface` internal
* removed the second and third argument of `KernelInterface::locateResource`
* removed the second and third argument of `FileLocator::__construct`
* removed loading resources from `%kernel.root_dir%/Resources` and `%kernel.root_dir%` as
fallback directories.
* removed class `ExceptionListener`, use `ErrorListener` instead
4.4.0
-----

View File

@@ -20,8 +20,6 @@ interface CacheClearerInterface
{
/**
* Clears any caches necessary.
*
* @param string $cacheDir The cache directory
*/
public function clear($cacheDir);
public function clear(string $cacheDir);
}

View File

@@ -22,6 +22,9 @@ class ChainCacheClearer implements CacheClearerInterface
{
private $clearers;
/**
* @param iterable<mixed, CacheClearerInterface> $clearers
*/
public function __construct(iterable $clearers = [])
{
$this->clearers = $clearers;
@@ -30,7 +33,7 @@ class ChainCacheClearer implements CacheClearerInterface
/**
* {@inheritdoc}
*/
public function clear($cacheDir)
public function clear(string $cacheDir)
{
foreach ($this->clearers as $clearer) {
$clearer->clear($cacheDir);

View File

@@ -11,6 +11,8 @@
namespace Symfony\Component\HttpKernel\CacheClearer;
use Psr\Cache\CacheItemPoolInterface;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
@@ -18,17 +20,28 @@ class Psr6CacheClearer implements CacheClearerInterface
{
private $pools = [];
/**
* @param array<string, CacheItemPoolInterface> $pools
*/
public function __construct(array $pools = [])
{
$this->pools = $pools;
}
public function hasPool($name)
/**
* @return bool
*/
public function hasPool(string $name)
{
return isset($this->pools[$name]);
}
public function getPool($name)
/**
* @return CacheItemPoolInterface
*
* @throws \InvalidArgumentException If the cache pool with the given name does not exist
*/
public function getPool(string $name)
{
if (!$this->hasPool($name)) {
throw new \InvalidArgumentException(sprintf('Cache pool not found: "%s".', $name));
@@ -37,7 +50,12 @@ class Psr6CacheClearer implements CacheClearerInterface
return $this->pools[$name];
}
public function clearPool($name)
/**
* @return bool
*
* @throws \InvalidArgumentException If the cache pool with the given name does not exist
*/
public function clearPool(string $name)
{
if (!isset($this->pools[$name])) {
throw new \InvalidArgumentException(sprintf('Cache pool not found: "%s".', $name));
@@ -49,7 +67,7 @@ class Psr6CacheClearer implements CacheClearerInterface
/**
* {@inheritdoc}
*/
public function clear($cacheDir)
public function clear(string $cacheDir)
{
foreach ($this->pools as $pool) {
$pool->clear();

View File

@@ -18,7 +18,7 @@ namespace Symfony\Component\HttpKernel\CacheWarmer;
*/
abstract class CacheWarmer implements CacheWarmerInterface
{
protected function writeCacheFile($file, $content)
protected function writeCacheFile(string $file, $content)
{
$tmpFile = @tempnam(\dirname($file), basename($file));
if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $file)) {

View File

@@ -26,6 +26,9 @@ class CacheWarmerAggregate implements CacheWarmerInterface
private $optionalsEnabled = false;
private $onlyOptionalsEnabled = false;
/**
* @param iterable<mixed, CacheWarmerInterface> $warmers
*/
public function __construct(iterable $warmers = [], bool $debug = false, string $deprecationLogsFilepath = null)
{
$this->warmers = $warmers;
@@ -44,11 +47,9 @@ class CacheWarmerAggregate implements CacheWarmerInterface
}
/**
* Warms up the cache.
*
* @param string $cacheDir The cache directory
* {@inheritdoc}
*/
public function warmUp($cacheDir)
public function warmUp(string $cacheDir): array
{
if ($collectDeprecations = $this->debug && !\defined('PHPUNIT_COMPOSER_INSTALL')) {
$collectedLogs = [];
@@ -85,6 +86,7 @@ class CacheWarmerAggregate implements CacheWarmerInterface
});
}
$preload = [];
try {
foreach ($this->warmers as $warmer) {
if (!$this->optionalsEnabled && $warmer->isOptional()) {
@@ -94,13 +96,13 @@ class CacheWarmerAggregate implements CacheWarmerInterface
continue;
}
$warmer->warmUp($cacheDir);
$preload[] = array_values((array) $warmer->warmUp($cacheDir));
}
} finally {
if ($collectDeprecations) {
restore_error_handler();
if (file_exists($this->deprecationLogsFilepath)) {
if (is_file($this->deprecationLogsFilepath)) {
$previousLogs = unserialize(file_get_contents($this->deprecationLogsFilepath));
if (\is_array($previousLogs)) {
$collectedLogs = array_merge($previousLogs, $collectedLogs);
@@ -110,12 +112,12 @@ class CacheWarmerAggregate implements CacheWarmerInterface
file_put_contents($this->deprecationLogsFilepath, serialize(array_values($collectedLogs)));
}
}
return array_values(array_unique(array_merge([], ...$preload)));
}
/**
* Checks whether this warmer is optional or not.
*
* @return bool always false
* {@inheritdoc}
*/
public function isOptional(): bool
{

View File

@@ -26,7 +26,7 @@ interface CacheWarmerInterface extends WarmableInterface
* A warmer should return true if the cache can be
* generated incrementally and on-demand.
*
* @return bool true if the warmer is optional, false otherwise
* @return bool
*/
public function isOptional();
}

View File

@@ -21,7 +21,7 @@ interface WarmableInterface
/**
* Warms up the cache.
*
* @param string $cacheDir The cache directory
* @return string[] A list of classes or files to preload on PHP 7.4+
*/
public function warmUp($cacheDir);
public function warmUp(string $cacheDir);
}

View File

@@ -1,201 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel;
use Symfony\Component\BrowserKit\AbstractBrowser;
use Symfony\Component\BrowserKit\CookieJar;
use Symfony\Component\BrowserKit\History;
use Symfony\Component\BrowserKit\Request as DomRequest;
use Symfony\Component\BrowserKit\Response as DomResponse;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* 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 AbstractBrowser
{
protected $kernel;
private $catchExceptions = true;
/**
* @param array $server The server parameters (equivalent of $_SERVER)
*/
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;
$this->followRedirects = false;
parent::__construct($server, $history, $cookieJar);
}
/**
* Sets whether to catch exceptions when the kernel is handling a request.
*
* @param bool $catchExceptions Whether to catch exceptions
*/
public function catchExceptions($catchExceptions)
{
$this->catchExceptions = $catchExceptions;
}
/**
* Makes a request.
*
* @return Response A Response instance
*/
protected function doRequest($request)
{
$response = $this->kernel->handle($request, HttpKernelInterface::MASTER_REQUEST, $this->catchExceptions);
if ($this->kernel instanceof TerminableInterface) {
$this->kernel->terminate($request, $response);
}
return $response;
}
/**
* Returns the script to execute when the request must be insulated.
*
* @return string
*/
protected function getScript($request)
{
$kernel = var_export(serialize($this->kernel), true);
$request = var_export(serialize($request), true);
$errorReporting = error_reporting();
$requires = '';
foreach (get_declared_classes() as $class) {
if (str_starts_with($class, 'ComposerAutoloaderInit')) {
$r = new \ReflectionClass($class);
$file = \dirname($r->getFileName(), 2).'/autoload.php';
if (file_exists($file)) {
$requires .= 'require_once '.var_export($file, true).";\n";
}
}
}
if (!$requires) {
throw new \RuntimeException('Composer autoloader not found.');
}
$code = <<<EOF
<?php
error_reporting($errorReporting);
$requires
\$kernel = unserialize($kernel);
\$request = unserialize($request);
EOF;
return $code.$this->getHandleScript();
}
protected function getHandleScript()
{
return <<<'EOF'
$response = $kernel->handle($request);
if ($kernel instanceof Symfony\Component\HttpKernel\TerminableInterface) {
$kernel->terminate($request, $response);
}
echo serialize($response);
EOF;
}
/**
* Converts the BrowserKit request to a HttpKernel request.
*
* @return Request A Request instance
*/
protected function filterRequest(DomRequest $request)
{
$httpRequest = Request::create($request->getUri(), $request->getMethod(), $request->getParameters(), $request->getCookies(), $request->getFiles(), $request->getServer(), $request->getContent());
foreach ($this->filterFiles($httpRequest->files->all()) as $key => $value) {
$httpRequest->files->set($key, $value);
}
return $httpRequest;
}
/**
* Filters an array of files.
*
* This method created test instances of UploadedFile so that the move()
* method can be called on those instances.
*
* If the size of a file is greater than the allowed size (from php.ini) then
* an invalid UploadedFile is returned with an error set to UPLOAD_ERR_INI_SIZE.
*
* @see UploadedFile
*
* @return array An array with all uploaded files marked as already moved
*/
protected function filterFiles(array $files)
{
$filtered = [];
foreach ($files as $key => $value) {
if (\is_array($value)) {
$filtered[$key] = $this->filterFiles($value);
} elseif ($value instanceof UploadedFile) {
if ($value->isValid() && $value->getSize() > UploadedFile::getMaxFilesize()) {
$filtered[$key] = new UploadedFile(
'',
$value->getClientOriginalName(),
$value->getClientMimeType(),
\UPLOAD_ERR_INI_SIZE,
true
);
} else {
$filtered[$key] = new UploadedFile(
$value->getPathname(),
$value->getClientOriginalName(),
$value->getClientMimeType(),
$value->getError(),
true
);
}
}
}
return $filtered;
}
/**
* Converts the HttpKernel response to a BrowserKit response.
*
* @return DomResponse A DomResponse instance
*/
protected function filterResponse($response)
{
// this is needed to support StreamedResponse
ob_start();
$response->sendContent();
$content = ob_get_clean();
return new DomResponse($content, $response->getStatusCode(), $response->headers->all());
}
}

View File

@@ -23,68 +23,24 @@ class FileLocator extends BaseFileLocator
{
private $kernel;
/**
* @deprecated since Symfony 4.4
*/
private $path;
public function __construct(KernelInterface $kernel/* , string $path = null, array $paths = [], bool $triggerDeprecation = true */)
public function __construct(KernelInterface $kernel)
{
$this->kernel = $kernel;
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);
parent::__construct();
}
/**
* {@inheritdoc}
*/
public function locate($file, $currentPath = null, $first = true)
public function locate(string $file, string $currentPath = null, bool $first = true)
{
if (isset($file[0]) && '@' === $file[0]) {
return $this->kernel->locateResource($file, $this->path, $first, false);
$resource = $this->kernel->locateResource($file);
return $first ? $resource : [$resource];
}
$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;
return parent::locate($file, $currentPath, $first);
}
}

View File

@@ -28,12 +28,11 @@ use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactoryInter
final class ArgumentResolver implements ArgumentResolverInterface
{
private $argumentMetadataFactory;
/**
* @var iterable|ArgumentValueResolverInterface[]
*/
private $argumentValueResolvers;
/**
* @param iterable<mixed, ArgumentValueResolverInterface> $argumentValueResolvers
*/
public function __construct(ArgumentMetadataFactoryInterface $argumentMetadataFactory = null, iterable $argumentValueResolvers = [])
{
$this->argumentMetadataFactory = $argumentMetadataFactory ?? new ArgumentMetadataFactory();
@@ -43,7 +42,7 @@ final class ArgumentResolver implements ArgumentResolverInterface
/**
* {@inheritdoc}
*/
public function getArguments(Request $request, $controller): array
public function getArguments(Request $request, callable $controller): array
{
$arguments = [];
@@ -62,7 +61,7 @@ final class ArgumentResolver implements ArgumentResolverInterface
}
if (!$atLeastOne) {
throw new \InvalidArgumentException(sprintf('"%s::resolve()" must yield at least one value.', \get_class($resolver)));
throw new \InvalidArgumentException(sprintf('"%s::resolve()" must yield at least one value.', get_debug_type($resolver)));
}
// continue to the next controller argument
@@ -83,6 +82,9 @@ final class ArgumentResolver implements ArgumentResolverInterface
return $arguments;
}
/**
* @return iterable<int, ArgumentValueResolverInterface>
*/
public static function getDefaultArgumentValueResolvers(): iterable
{
return [

View File

@@ -38,7 +38,7 @@ final class VariadicValueResolver implements ArgumentValueResolverInterface
$values = $request->attributes->get($argument->getName());
if (!\is_array($values)) {
throw new \InvalidArgumentException(sprintf('The action argument "...$%1$s" is required to be an array, the request attribute "%1$s" contains a type of "%2$s" instead.', $argument->getName(), \gettype($values)));
throw new \InvalidArgumentException(sprintf('The action argument "...$%1$s" is required to be an array, the request attribute "%1$s" contains a type of "%2$s" instead.', $argument->getName(), get_debug_type($values)));
}
yield from $values;

View File

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

View File

@@ -16,7 +16,7 @@ use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\Container;
/**
* A controller resolver searching for a controller in a psr-11 container when using the "service:method" notation.
* A controller resolver searching for a controller in a psr-11 container when using the "service::method" notation.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
@@ -32,11 +32,11 @@ class ContainerControllerResolver extends ControllerResolver
parent::__construct($logger);
}
protected function createController($controller)
protected function createController(string $controller)
{
if (1 === substr_count($controller, ':')) {
$controller = str_replace(':', '::', $controller);
// TODO deprecate this in 5.1
trigger_deprecation('symfony/http-kernel', '5.1', 'Referencing controllers with a single colon is deprecated. Use "%s" instead.', $controller);
}
return parent::createController($controller);
@@ -45,7 +45,7 @@ class ContainerControllerResolver extends ControllerResolver
/**
* {@inheritdoc}
*/
protected function instantiateController($class)
protected function instantiateController(string $class)
{
$class = ltrim($class, '\\');

View File

@@ -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: '.$this->getControllerError($controller), $request->getPathInfo()));
throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$this->getControllerError($controller));
}
return $controller;
@@ -89,7 +89,7 @@ class ControllerResolver implements ControllerResolverInterface
}
if (!\is_callable($callable)) {
throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: '.$this->getControllerError($callable), $request->getPathInfo()));
throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$this->getControllerError($callable));
}
return $callable;
@@ -98,13 +98,11 @@ class ControllerResolver implements ControllerResolverInterface
/**
* Returns a callable for the given controller.
*
* @param string $controller A Controller string
*
* @return callable A PHP callable
* @return callable
*
* @throws \InvalidArgumentException When the controller cannot be created
*/
protected function createController($controller)
protected function createController(string $controller)
{
if (!str_contains($controller, '::')) {
$controller = $this->instantiateController($controller);
@@ -142,11 +140,9 @@ class ControllerResolver implements ControllerResolverInterface
/**
* Returns an instantiated controller.
*
* @param string $class A class name
*
* @return object
*/
protected function instantiateController($class)
protected function instantiateController(string $class)
{
return new $class();
}
@@ -165,11 +161,11 @@ class ControllerResolver implements ControllerResolverInterface
$availableMethods = $this->getClassMethodsWithoutMagicMethods($callable);
$alternativeMsg = $availableMethods ? sprintf(' or use one of the available methods: "%s"', implode('", "', $availableMethods)) : '';
return sprintf('Controller class "%s" cannot be called without a method name. You need to implement "__invoke"%s.', \get_class($callable), $alternativeMsg);
return sprintf('Controller class "%s" cannot be called without a method name. You need to implement "__invoke"%s.', get_debug_type($callable), $alternativeMsg);
}
if (!\is_array($callable)) {
return sprintf('Invalid type for controller given, expected string, array or object, got "%s".', \gettype($callable));
return sprintf('Invalid type for controller given, expected string, array or object, got "%s".', get_debug_type($callable));
}
if (!isset($callable[0]) || !isset($callable[1]) || 2 !== \count($callable)) {
@@ -182,7 +178,7 @@ class ControllerResolver implements ControllerResolverInterface
return sprintf('Class "%s" does not exist.', $controller);
}
$className = \is_object($controller) ? \get_class($controller) : $controller;
$className = \is_object($controller) ? get_debug_type($controller) : $controller;
if (method_exists($controller, $method)) {
return sprintf('Method "%s" on class "%s" should be public and non-abstract.', $method, $className);

View File

@@ -31,7 +31,7 @@ class TraceableArgumentResolver implements ArgumentResolverInterface
/**
* {@inheritdoc}
*/
public function getArguments(Request $request, $controller)
public function getArguments(Request $request, callable $controller)
{
$e = $this->stopwatch->start('controller.get_arguments');

View File

@@ -11,6 +11,8 @@
namespace Symfony\Component\HttpKernel\ControllerMetadata;
use Symfony\Component\HttpKernel\Attribute\ArgumentInterface;
/**
* Responsible for storing metadata of an argument.
*
@@ -18,14 +20,20 @@ namespace Symfony\Component\HttpKernel\ControllerMetadata;
*/
class ArgumentMetadata
{
public const IS_INSTANCEOF = 2;
private $name;
private $type;
private $isVariadic;
private $hasDefaultValue;
private $defaultValue;
private $isNullable;
private $attributes;
public function __construct(string $name, ?string $type, bool $isVariadic, bool $hasDefaultValue, $defaultValue, bool $isNullable = false)
/**
* @param object[] $attributes
*/
public function __construct(string $name, ?string $type, bool $isVariadic, bool $hasDefaultValue, $defaultValue, bool $isNullable = false, $attributes = [])
{
$this->name = $name;
$this->type = $type;
@@ -33,6 +41,13 @@ class ArgumentMetadata
$this->hasDefaultValue = $hasDefaultValue;
$this->defaultValue = $defaultValue;
$this->isNullable = $isNullable || null === $type || ($hasDefaultValue && null === $defaultValue);
if (null === $attributes || $attributes instanceof ArgumentInterface) {
trigger_deprecation('symfony/http-kernel', '5.3', 'The "%s" constructor expects an array of PHP attributes as last argument, %s given.', __CLASS__, get_debug_type($attributes));
$attributes = $attributes ? [$attributes] : [];
}
$this->attributes = $attributes;
}
/**
@@ -104,4 +119,45 @@ class ArgumentMetadata
return $this->defaultValue;
}
/**
* Returns the attribute (if any) that was set on the argument.
*/
public function getAttribute(): ?ArgumentInterface
{
trigger_deprecation('symfony/http-kernel', '5.3', 'Method "%s()" is deprecated, use "getAttributes()" instead.', __METHOD__);
if (!$this->attributes) {
return null;
}
return $this->attributes[0] instanceof ArgumentInterface ? $this->attributes[0] : null;
}
/**
* @return object[]
*/
public function getAttributes(string $name = null, int $flags = 0): array
{
if (!$name) {
return $this->attributes;
}
$attributes = [];
if ($flags & self::IS_INSTANCEOF) {
foreach ($this->attributes as $attribute) {
if ($attribute instanceof $name) {
$attributes[] = $attribute;
}
}
} else {
foreach ($this->attributes as $attribute) {
if (\get_class($attribute) === $name) {
$attributes[] = $attribute;
}
}
}
return $attributes;
}
}

View File

@@ -33,13 +33,22 @@ final class ArgumentMetadataFactory implements ArgumentMetadataFactoryInterface
$class = $reflection->class;
} else {
$reflection = new \ReflectionFunction($controller);
if ($class = str_contains($reflection->name, '{closure}') ? null : $reflection->getClosureScopeClass()) {
if ($class = str_contains($reflection->name, '{closure}') ? null : (\PHP_VERSION_ID >= 80111 ? $reflection->getClosureCalledClass() : $reflection->getClosureScopeClass())) {
$class = $class->name;
}
}
foreach ($reflection->getParameters() as $param) {
$arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $class), $param->isVariadic(), $param->isDefaultValueAvailable(), $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, $param->allowsNull());
$attributes = [];
if (\PHP_VERSION_ID >= 80000) {
foreach ($param->getAttributes() as $reflectionAttribute) {
if (class_exists($reflectionAttribute->getName())) {
$attributes[] = $reflectionAttribute->newInstance();
}
}
}
$arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $class), $param->isVariadic(), $param->isDefaultValueAvailable(), $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, $param->allowsNull(), $attributes);
}
return $arguments;

View File

@@ -15,20 +15,13 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* AjaxDataCollector.
*
* @author Bart van den Burg <bart@burgov.nl>
*
* @final since Symfony 4.4
* @final
*/
class AjaxDataCollector extends DataCollector
{
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
public function collect(Request $request, Response $response, \Throwable $exception = null)
{
// all collecting is done client side
}
@@ -38,7 +31,7 @@ class AjaxDataCollector extends DataCollector
// all collecting is done client side
}
public function getName()
public function getName(): string
{
return 'ajax';
}

View File

@@ -20,7 +20,7 @@ use Symfony\Component\VarDumper\Caster\ClassStub;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.4
* @final
*/
class ConfigDataCollector extends DataCollector implements LateDataCollectorInterface
{
@@ -28,21 +28,6 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
* @var KernelInterface
*/
private $kernel;
private $name;
private $version;
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);
}
if (2 <= \func_num_args()) {
@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;
}
/**
* Sets the Kernel associated with this Request.
@@ -54,17 +39,13 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
public function collect(Request $request, Response $response, \Throwable $exception = null)
{
$eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE);
$eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE);
$this->data = [
'app_name' => $this->name,
'app_version' => $this->version,
'token' => $response->headers->get('X-Debug-Token'),
'symfony_version' => Kernel::VERSION,
'symfony_minor_version' => sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION),
@@ -110,42 +91,18 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
$this->data = $this->cloneVar($this->data);
}
/**
* @deprecated since Symfony 4.2
*/
public function getApplicationName()
{
@trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED);
return $this->data['app_name'];
}
/**
* @deprecated since Symfony 4.2
*/
public function getApplicationVersion()
{
@trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED);
return $this->data['app_version'];
}
/**
* Gets the token.
*
* @return string|null The token
*/
public function getToken()
public function getToken(): ?string
{
return $this->data['token'];
}
/**
* Gets the Symfony version.
*
* @return string The Symfony version
*/
public function getSymfonyVersion()
public function getSymfonyVersion(): string
{
return $this->data['symfony_version'];
}
@@ -155,7 +112,7 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
*
* @return string One of: unknown, dev, stable, eom, eol
*/
public function getSymfonyState()
public function getSymfonyState(): string
{
return $this->data['symfony_state'];
}
@@ -163,10 +120,8 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
/**
* Returns the minor Symfony version used (without patch numbers of extra
* suffix like "RC", "beta", etc.).
*
* @return string
*/
public function getSymfonyMinorVersion()
public function getSymfonyMinorVersion(): string
{
return $this->data['symfony_minor_version'];
}
@@ -182,10 +137,8 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
/**
* Returns the human readable date when this Symfony version ends its
* maintenance period.
*
* @return string
*/
public function getSymfonyEom()
public function getSymfonyEom(): string
{
return $this->data['symfony_eom'];
}
@@ -193,30 +146,24 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
/**
* Returns the human readable date when this Symfony version reaches its
* "end of life" and won't receive bugs or security fixes.
*
* @return string
*/
public function getSymfonyEol()
public function getSymfonyEol(): string
{
return $this->data['symfony_eol'];
}
/**
* Gets the PHP version.
*
* @return string The PHP version
*/
public function getPhpVersion()
public function getPhpVersion(): string
{
return $this->data['php_version'];
}
/**
* Gets the PHP version extra part.
*
* @return string|null The extra part
*/
public function getPhpVersionExtra()
public function getPhpVersionExtra(): ?string
{
return $this->data['php_version_extra'] ?? null;
}
@@ -224,47 +171,25 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
/**
* @return int The PHP architecture as number of bits (e.g. 32 or 64)
*/
public function getPhpArchitecture()
public function getPhpArchitecture(): int
{
return $this->data['php_architecture'];
}
/**
* @return string
*/
public function getPhpIntlLocale()
public function getPhpIntlLocale(): string
{
return $this->data['php_intl_locale'];
}
/**
* @return string
*/
public function getPhpTimezone()
public function getPhpTimezone(): string
{
return $this->data['php_timezone'];
}
/**
* Gets the application name.
*
* @return string The application name
*
* @deprecated since Symfony 4.2
*/
public function getAppName()
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED);
return 'n/a';
}
/**
* Gets the environment.
*
* @return string The environment
*/
public function getEnv()
public function getEnv(): string
{
return $this->data['env'];
}
@@ -272,7 +197,7 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
/**
* Returns true if the debug is enabled.
*
* @return bool true if debug is enabled, false otherwise
* @return bool|string true if debug is enabled, false otherwise or a string if no kernel was set
*/
public function isDebug()
{
@@ -281,30 +206,24 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
/**
* Returns true if the XDebug is enabled.
*
* @return bool true if XDebug is enabled, false otherwise
*/
public function hasXDebug()
public function hasXDebug(): bool
{
return $this->data['xdebug_enabled'];
}
/**
* Returns true if APCu is enabled.
*
* @return bool true if APCu is enabled, false otherwise
*/
public function hasApcu()
public function hasApcu(): bool
{
return $this->data['apcu_enabled'];
}
/**
* Returns true if Zend OPcache is enabled.
*
* @return bool true if Zend OPcache is enabled, false otherwise
*/
public function hasZendOpcache()
public function hasZendOpcache(): bool
{
return $this->data['zend_opcache_enabled'];
}
@@ -316,10 +235,8 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
/**
* Gets the PHP SAPI name.
*
* @return string The environment
*/
public function getSapiName()
public function getSapiName(): string
{
return $this->data['sapi_name'];
}
@@ -327,7 +244,7 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
/**
* {@inheritdoc}
*/
public function getName()
public function getName(): string
{
return 'config';
}

View File

@@ -38,29 +38,6 @@ abstract class DataCollector implements DataCollectorInterface
*/
private $cloner;
/**
* @deprecated since Symfony 4.3, store all the serialized state in the data property instead
*/
public function serialize()
{
@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)
{
@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);
}
/**
* Converts the variable into a serializable Data instance.
*
@@ -112,23 +89,24 @@ abstract class DataCollector implements DataCollectorInterface
*/
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);
}
/**
* @internal to prevent implementing \Serializable
*/
final protected function serialize()
{
}
/**
* @internal to prevent implementing \Serializable
*/
final protected function unserialize($data)
{
}
}

View File

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

View File

@@ -27,7 +27,7 @@ use Symfony\Component\VarDumper\Server\Connection;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.3
* @final
*/
class DumpDataCollector extends DataCollector implements DataDumperInterface
{
@@ -101,19 +101,14 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
}
}
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
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')) {
if ($this->dumper || ($this->requestStack && $this->requestStack->getMainRequest() !== $request) || $request->isXmlHttpRequest() || $request->headers->has('Origin')) {
return;
}
@@ -193,12 +188,12 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
self::__construct($this->stopwatch, \is_string($fileLinkFormat) || $fileLinkFormat instanceof FileLinkFormatter ? $fileLinkFormat : null, \is_string($charset) ? $charset : null);
}
public function getDumpsCount()
public function getDumpsCount(): int
{
return $this->dataCount;
}
public function getDumps($format, $maxDepthLimit = -1, $maxItemsPerDepth = -1)
public function getDumps(string $format, int $maxDepthLimit = -1, int $maxItemsPerDepth = -1): array
{
$data = fopen('php://memory', 'r+');
@@ -225,7 +220,7 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
return $dumps;
}
public function getName()
public function getName(): string
{
return 'dump';
}

View File

@@ -12,19 +12,17 @@
namespace Symfony\Component\HttpKernel\DataCollector;
use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher;
use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\Service\ResetInterface;
/**
* EventDataCollector.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.4
* @final
*/
class EventDataCollector extends DataCollector implements LateDataCollectorInterface
{
@@ -40,12 +38,10 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
public function collect(Request $request, Response $response, \Throwable $exception = null)
{
$this->currentRequest = $this->requestStack && $this->requestStack->getMasterRequest() !== $request ? $request : null;
$this->currentRequest = $this->requestStack && $this->requestStack->getMainRequest() !== $request ? $request : null;
$this->data = [
'called_listeners' => [],
'not_called_listeners' => [],
@@ -64,12 +60,9 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
public function lateCollect()
{
if ($this->dispatcher instanceof TraceableEventDispatcherInterface) {
if ($this->dispatcher instanceof TraceableEventDispatcher) {
$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->currentRequest));
}
@@ -77,8 +70,6 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
}
/**
* Sets the called listeners.
*
* @param array $listeners An array of called listeners
*
* @see TraceableEventDispatcher
@@ -89,11 +80,9 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
}
/**
* Gets the called listeners.
*
* @return array An array of called listeners
*
* @see TraceableEventDispatcher
*
* @return array|Data
*/
public function getCalledListeners()
{
@@ -101,8 +90,6 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
}
/**
* Sets the not called listeners.
*
* @see TraceableEventDispatcher
*/
public function setNotCalledListeners(array $listeners)
@@ -111,11 +98,9 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
}
/**
* Gets the not called listeners.
*
* @return array
*
* @see TraceableEventDispatcher
*
* @return array|Data
*/
public function getNotCalledListeners()
{
@@ -123,8 +108,6 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
}
/**
* Sets the orphaned events.
*
* @param array $events An array of orphaned events
*
* @see TraceableEventDispatcher
@@ -135,11 +118,9 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
}
/**
* Gets the orphaned events.
*
* @return array An array of orphaned events
*
* @see TraceableEventDispatcher
*
* @return array|Data
*/
public function getOrphanedEvents()
{
@@ -149,7 +130,7 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
/**
* {@inheritdoc}
*/
public function getName()
public function getName(): string
{
return 'events';
}

View File

@@ -16,23 +16,17 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* ExceptionDataCollector.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.4
* @final
*/
class ExceptionDataCollector extends DataCollector
{
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response/* , \Throwable $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 = [
'exception' => FlattenException::createFromThrowable($exception),
@@ -48,19 +42,12 @@ class ExceptionDataCollector extends DataCollector
$this->data = [];
}
/**
* Checks if the exception is not null.
*
* @return bool true if the exception is not null, false otherwise
*/
public function hasException()
public function hasException(): bool
{
return isset($this->data['exception']);
}
/**
* Gets the exception.
*
* @return \Exception|FlattenException
*/
public function getException()
@@ -68,42 +55,22 @@ class ExceptionDataCollector extends DataCollector
return $this->data['exception'];
}
/**
* Gets the exception message.
*
* @return string The exception message
*/
public function getMessage()
public function getMessage(): string
{
return $this->data['exception']->getMessage();
}
/**
* Gets the exception code.
*
* @return int The exception code
*/
public function getCode()
public function getCode(): int
{
return $this->data['exception']->getCode();
}
/**
* Gets the status code.
*
* @return int The status code
*/
public function getStatusCode()
public function getStatusCode(): int
{
return $this->data['exception']->getStatusCode();
}
/**
* Gets the exception trace.
*
* @return array The exception trace
*/
public function getTrace()
public function getTrace(): array
{
return $this->data['exception']->getTrace();
}
@@ -111,7 +78,7 @@ class ExceptionDataCollector extends DataCollector
/**
* {@inheritdoc}
*/
public function getName()
public function getName(): string
{
return 'exception';
}

View File

@@ -20,7 +20,7 @@ use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.4
* @final
*/
class LoggerDataCollector extends DataCollector implements LateDataCollectorInterface
{
@@ -28,8 +28,9 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
private $containerPathPrefix;
private $currentRequest;
private $requestStack;
private $processedLogs;
public function __construct($logger = null, string $containerPathPrefix = null, RequestStack $requestStack = null)
public function __construct(object $logger = null, string $containerPathPrefix = null, RequestStack $requestStack = null)
{
if (null !== $logger && $logger instanceof DebugLoggerInterface) {
$this->logger = $logger;
@@ -41,12 +42,10 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
public function collect(Request $request, Response $response, \Throwable $exception = null)
{
$this->currentRequest = $this->requestStack && $this->requestStack->getMasterRequest() !== $request ? $request : null;
$this->currentRequest = $this->requestStack && $this->requestStack->getMainRequest() !== $request ? $request : null;
}
/**
@@ -82,6 +81,82 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
return $this->data['logs'] ?? [];
}
public function getProcessedLogs()
{
if (null !== $this->processedLogs) {
return $this->processedLogs;
}
$rawLogs = $this->getLogs();
if ([] === $rawLogs) {
return $this->processedLogs = $rawLogs;
}
$logs = [];
foreach ($this->getLogs()->getValue() as $rawLog) {
$rawLogData = $rawLog->getValue();
if ($rawLogData['priority']->getValue() > 300) {
$logType = 'error';
} elseif (isset($rawLogData['scream']) && false === $rawLogData['scream']->getValue()) {
$logType = 'deprecation';
} elseif (isset($rawLogData['scream']) && true === $rawLogData['scream']->getValue()) {
$logType = 'silenced';
} else {
$logType = 'regular';
}
$logs[] = [
'type' => $logType,
'errorCount' => $rawLog['errorCount'] ?? 1,
'timestamp' => $rawLogData['timestamp_rfc3339']->getValue(),
'priority' => $rawLogData['priority']->getValue(),
'priorityName' => $rawLogData['priorityName']->getValue(),
'channel' => $rawLogData['channel']->getValue(),
'message' => $rawLogData['message'],
'context' => $rawLogData['context'],
];
}
// sort logs from oldest to newest
usort($logs, static function ($logA, $logB) {
return $logA['timestamp'] <=> $logB['timestamp'];
});
return $this->processedLogs = $logs;
}
public function getFilters()
{
$filters = [
'channel' => [],
'priority' => [
'Debug' => 100,
'Info' => 200,
'Notice' => 250,
'Warning' => 300,
'Error' => 400,
'Critical' => 500,
'Alert' => 550,
'Emergency' => 600,
],
];
$allChannels = [];
foreach ($this->getProcessedLogs() as $log) {
if ('' === trim($log['channel'] ?? '')) {
continue;
}
$allChannels[] = $log['channel'];
}
$channels = array_unique($allChannels);
sort($channels);
$filters['channel'] = $channels;
return $filters;
}
public function getPriorities()
{
return $this->data['priorities'] ?? [];
@@ -115,14 +190,14 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
/**
* {@inheritdoc}
*/
public function getName()
public function getName(): string
{
return 'logger';
}
private function getContainerDeprecationLogs(): array
{
if (null === $this->containerPathPrefix || !file_exists($file = $this->containerPathPrefix.'Deprecations.log')) {
if (null === $this->containerPathPrefix || !is_file($file = $this->containerPathPrefix.'Deprecations.log')) {
return [];
}
@@ -135,6 +210,7 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
foreach (unserialize($logContent) as $log) {
$log['context'] = ['exception' => new SilencedErrorContext($log['type'], $log['file'], $log['line'], $log['trace'], $log['count'])];
$log['timestamp'] = $bootTime;
$log['timestamp_rfc3339'] = (new \DateTimeImmutable())->setTimestamp($bootTime)->format(\DateTimeInterface::RFC3339_EXTENDED);
$log['priority'] = 100;
$log['priorityName'] = 'DEBUG';
$log['channel'] = null;
@@ -148,7 +224,7 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
private function getContainerCompilerLogs(string $compilerLogsFilepath = null): array
{
if (!file_exists($compilerLogsFilepath)) {
if (!is_file($compilerLogsFilepath)) {
return [];
}

View File

@@ -15,11 +15,9 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* MemoryDataCollector.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.4
* @final
*/
class MemoryDataCollector extends DataCollector implements LateDataCollectorInterface
{
@@ -30,10 +28,8 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
public function collect(Request $request, Response $response, \Throwable $exception = null)
{
$this->updateMemoryUsage();
}
@@ -57,29 +53,19 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte
$this->updateMemoryUsage();
}
/**
* Gets the memory.
*
* @return int The memory
*/
public function getMemory()
public function getMemory(): int
{
return $this->data['memory'];
}
/**
* Gets the PHP memory limit.
*
* @return int The memory limit
* @return int|float
*/
public function getMemoryLimit()
{
return $this->data['memory_limit'];
}
/**
* Updates the memory usage data.
*/
public function updateMemoryUsage()
{
$this->data['memory'] = memory_get_peak_usage(true);
@@ -88,7 +74,7 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte
/**
* {@inheritdoc}
*/
public function getName()
public function getName(): string
{
return 'memory';
}

View File

@@ -15,31 +15,39 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\VarDumper\Cloner\Data;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.4
* @final
*/
class RequestDataCollector extends DataCollector implements EventSubscriberInterface, LateDataCollectorInterface
{
protected $controllers;
/**
* @var \SplObjectStorage<Request, callable>
*/
private $controllers;
private $sessionUsages = [];
private $requestStack;
public function __construct()
public function __construct(RequestStack $requestStack = null)
{
$this->controllers = new \SplObjectStorage();
$this->requestStack = $requestStack;
}
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response/* , \Throwable $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 = [];
@@ -86,7 +94,6 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
$this->data = [
'method' => $request->getMethod(),
'format' => $request->getRequestFormat(),
'content' => $content,
'content_type' => $response->headers->get('Content-Type', 'text/html'),
'status_text' => Response::$statusTexts[$statusCode] ?? '',
'status_code' => $statusCode,
@@ -102,6 +109,8 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
'response_cookies' => $responseCookies,
'session_metadata' => $sessionMetadata,
'session_attributes' => $sessionAttributes,
'session_usages' => array_values($this->sessionUsages),
'stateless_check' => $this->requestStack && ($mainRequest = $this->requestStack->getMainRequest()) && $mainRequest->attributes->get('_stateless', false),
'flashes' => $flashes,
'path_info' => $request->getPathInfo(),
'controller' => 'n/a',
@@ -118,9 +127,13 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
}
if (isset($this->data['request_request']['_password'])) {
$encodedPassword = rawurlencode($this->data['request_request']['_password']);
$content = str_replace('_password='.$encodedPassword, '_password=******', $content);
$this->data['request_request']['_password'] = '******';
}
$this->data['content'] = $content;
foreach ($this->data as $key => $value) {
if (!\is_array($value)) {
continue;
@@ -172,6 +185,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
{
$this->data = [];
$this->controllers = new \SplObjectStorage();
$this->sessionUsages = [];
}
public function getMethod()
@@ -204,12 +218,12 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
return new ParameterBag($this->data['request_headers']->getValue());
}
public function getRequestServer($raw = false)
public function getRequestServer(bool $raw = false)
{
return new ParameterBag($this->data['request_server']->getValue($raw));
}
public function getRequestCookies($raw = false)
public function getRequestCookies(bool $raw = false)
{
return new ParameterBag($this->data['request_cookies']->getValue($raw));
}
@@ -239,6 +253,16 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
return $this->data['session_attributes']->getValue();
}
public function getStatelessCheck()
{
return $this->data['stateless_check'];
}
public function getSessionUsages()
{
return $this->data['session_usages'];
}
public function getFlashes()
{
return $this->data['flashes']->getValue();
@@ -295,10 +319,8 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
* Gets the route name.
*
* The _route request attributes is automatically set by the Router Matcher.
*
* @return string The route
*/
public function getRoute()
public function getRoute(): string
{
return $this->data['route'];
}
@@ -312,10 +334,8 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
* Gets the route parameters.
*
* The _route_params request attributes is automatically set by the RouterListener.
*
* @return array The parameters
*/
public function getRouteParams()
public function getRouteParams(): array
{
return isset($this->data['request_attributes']['_route_params']) ? $this->data['request_attributes']['_route_params']->getValue() : [];
}
@@ -323,8 +343,8 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
/**
* Gets the parsed controller.
*
* @return array|string The controller as a string or array of data
* with keys 'class', 'method', 'file' and 'line'
* @return array|string|Data The controller as a string or array of data
* with keys 'class', 'method', 'file' and 'line'
*/
public function getController()
{
@@ -334,8 +354,8 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
/**
* Gets the previous request attributes.
*
* @return array|bool A legacy array of data from the previous redirection response
* or false otherwise
* @return array|Data|false A legacy array of data from the previous redirection response
* or false otherwise
*/
public function getRedirect()
{
@@ -347,20 +367,14 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
return $this->data['forward_token'] ?? null;
}
/**
* @final since Symfony 4.3
*/
public function onKernelController(FilterControllerEvent $event)
public function onKernelController(ControllerEvent $event)
{
$this->controllers[$event->getRequest()] = $event->getController();
}
/**
* @final since Symfony 4.3
*/
public function onKernelResponse(FilterResponseEvent $event)
public function onKernelResponse(ResponseEvent $event)
{
if (!$event->isMasterRequest()) {
if (!$event->isMainRequest()) {
return;
}
@@ -369,7 +383,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
}
}
public static function getSubscribedEvents()
public static function getSubscribedEvents(): array
{
return [
KernelEvents::CONTROLLER => 'onKernelController',
@@ -380,19 +394,48 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
/**
* {@inheritdoc}
*/
public function getName()
public function getName(): string
{
return 'request';
}
public function collectSessionUsage(): void
{
$trace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS);
$traceEndIndex = \count($trace) - 1;
for ($i = $traceEndIndex; $i > 0; --$i) {
if (null !== ($class = $trace[$i]['class'] ?? null) && (is_subclass_of($class, SessionInterface::class) || is_subclass_of($class, SessionBagInterface::class))) {
$traceEndIndex = $i;
break;
}
}
if ((\count($trace) - 1) === $traceEndIndex) {
return;
}
// Remove part of the backtrace that belongs to session only
array_splice($trace, 0, $traceEndIndex);
// Merge identical backtraces generated by internal call reports
$name = sprintf('%s:%s', $trace[1]['class'] ?? $trace[0]['file'], $trace[0]['line']);
if (!\array_key_exists($name, $this->sessionUsages)) {
$this->sessionUsages[$name] = [
'name' => $name,
'file' => $trace[0]['file'],
'line' => $trace[0]['line'],
'trace' => $trace,
];
}
}
/**
* Parse a controller.
*
* @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)
private function parseController($controller)
{
if (\is_string($controller) && str_contains($controller, '::')) {
$controller = explode('::', $controller);
@@ -403,7 +446,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
$r = new \ReflectionMethod($controller[0], $controller[1]);
return [
'class' => \is_object($controller[0]) ? \get_class($controller[0]) : $controller[0],
'class' => \is_object($controller[0]) ? get_debug_type($controller[0]) : $controller[0],
'method' => $controller[1],
'file' => $r->getFileName(),
'line' => $r->getStartLine(),
@@ -412,7 +455,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
if (\is_callable($controller)) {
// using __call or __callStatic
return [
'class' => \is_object($controller[0]) ? \get_class($controller[0]) : $controller[0],
'class' => \is_object($controller[0]) ? get_debug_type($controller[0]) : $controller[0],
'method' => $controller[1],
'file' => 'n/a',
'line' => 'n/a',
@@ -436,7 +479,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
}
$controller['method'] = $r->name;
if ($class = $r->getClosureScopeClass()) {
if ($class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) {
$controller['class'] = $class->name;
} else {
return $r->name;

View File

@@ -14,7 +14,7 @@ namespace Symfony\Component\HttpKernel\DataCollector;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
/**
* @author Fabien Potencier <fabien@symfony.com>
@@ -22,7 +22,7 @@ use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
class RouterDataCollector extends DataCollector
{
/**
* @var \SplObjectStorage
* @var \SplObjectStorage<Request, callable>
*/
protected $controllers;
@@ -34,11 +34,9 @@ class RouterDataCollector extends DataCollector
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*
* @final since Symfony 4.4
* @final
*/
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
public function collect(Request $request, Response $response, \Throwable $exception = null)
{
if ($response instanceof RedirectResponse) {
$this->data['redirect'] = true;
@@ -70,10 +68,8 @@ class RouterDataCollector extends DataCollector
/**
* Remembers the controller associated to each request.
*
* @final since Symfony 4.3
*/
public function onKernelController(FilterControllerEvent $event)
public function onKernelController(ControllerEvent $event)
{
$this->controllers[$event->getRequest()] = $event->getController();
}
@@ -87,7 +83,7 @@ class RouterDataCollector extends DataCollector
}
/**
* @return string|null The target URL
* @return string|null
*/
public function getTargetUrl()
{
@@ -95,7 +91,7 @@ class RouterDataCollector extends DataCollector
}
/**
* @return string|null The target route
* @return string|null
*/
public function getTargetRoute()
{

View File

@@ -20,12 +20,12 @@ use Symfony\Component\Stopwatch\StopwatchEvent;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.4
* @final
*/
class TimeDataCollector extends DataCollector implements LateDataCollectorInterface
{
protected $kernel;
protected $stopwatch;
private $kernel;
private $stopwatch;
public function __construct(KernelInterface $kernel = null, Stopwatch $stopwatch = null)
{
@@ -35,10 +35,8 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
/**
* {@inheritdoc}
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
public function collect(Request $request, Response $response, \Throwable $exception = null)
{
if (null !== $this->kernel) {
$startTime = $this->kernel->getStartTime();
@@ -78,8 +76,6 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
}
/**
* Sets the request events.
*
* @param StopwatchEvent[] $events The request events
*/
public function setEvents(array $events)
@@ -92,21 +88,17 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
}
/**
* Gets the request events.
*
* @return StopwatchEvent[] The request events
* @return StopwatchEvent[]
*/
public function getEvents()
public function getEvents(): array
{
return $this->data['events'];
}
/**
* Gets the request elapsed time.
*
* @return float The elapsed time
*/
public function getDuration()
public function getDuration(): float
{
if (!isset($this->data['events']['__section__'])) {
return 0;
@@ -121,10 +113,8 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
* Gets the initialization time.
*
* This is the time spent until the beginning of the request handling.
*
* @return float The elapsed time
*/
public function getInitTime()
public function getInitTime(): float
{
if (!isset($this->data['events']['__section__'])) {
return 0;
@@ -133,20 +123,12 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
return $this->data['events']['__section__']->getOrigin() - $this->getStartTime();
}
/**
* Gets the request time.
*
* @return float
*/
public function getStartTime()
public function getStartTime(): float
{
return $this->data['start_time'];
}
/**
* @return bool whether or not the stopwatch component is installed
*/
public function isStopwatchInstalled()
public function isStopwatchInstalled(): bool
{
return $this->data['stopwatch_installed'];
}
@@ -154,7 +136,7 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
/**
* {@inheritdoc}
*/
public function getName()
public function getName(): string
{
return 'time';
}

View File

@@ -20,10 +20,20 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
*
* @author Jérémy Romey <jeremy@free-agent.fr>
*
* @final since Symfony 4.3
* @final
*/
class FileLinkFormatter
{
private const FORMATS = [
'textmate' => 'txmt://open?url=file://%f&line=%l',
'macvim' => 'mvim://open?url=file://%f&line=%l',
'emacs' => 'emacs://open?url=file://%f&line=%l',
'sublime' => 'subl://open?url=file://%f&line=%l',
'phpstorm' => 'phpstorm://open?file=%f&line=%l',
'atom' => 'atom://core/open/file?filename=%f&line=%l',
'vscode' => 'vscode://file/%f:%l',
];
private $fileLinkFormat;
private $requestStack;
private $baseDir;
@@ -35,7 +45,7 @@ class FileLinkFormatter
*/
public function __construct($fileLinkFormat = null, RequestStack $requestStack = null, string $baseDir = null, $urlFormat = null)
{
if (!\is_array($fileLinkFormat) && $fileLinkFormat = $fileLinkFormat ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format')) {
if (!\is_array($fileLinkFormat) && $fileLinkFormat = (self::FORMATS[$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 = [substr($f, 0, $i)] + preg_split('/&([^>]++)>/', substr($f, $i), -1, \PREG_SPLIT_DELIM_CAPTURE);
}
@@ -46,7 +56,7 @@ class FileLinkFormatter
$this->urlFormat = $urlFormat;
}
public function format($file, $line)
public function format(string $file, int $line)
{
if ($fmt = $this->getFileLinkFormat()) {
for ($i = 1; isset($fmt[$i]); ++$i) {
@@ -75,7 +85,7 @@ class FileLinkFormatter
/**
* @internal
*/
public static function generateUrlFormat(UrlGeneratorInterface $router, $routeName, $queryString)
public static function generateUrlFormat(UrlGeneratorInterface $router, string $routeName, string $queryString): ?string
{
try {
return $router->generate($routeName).$queryString;
@@ -91,7 +101,7 @@ class FileLinkFormatter
}
if ($this->requestStack && $this->baseDir && $this->urlFormat) {
$request = $this->requestStack->getMasterRequest();
$request = $this->requestStack->getMainRequest();
if ($request instanceof Request && (!$this->urlFormat instanceof \Closure || $this->urlFormat = ($this->urlFormat)())) {
return [

View File

@@ -26,7 +26,7 @@ class TraceableEventDispatcher extends BaseTraceableEventDispatcher
/**
* {@inheritdoc}
*/
protected function beforeDispatch(string $eventName, $event)
protected function beforeDispatch(string $eventName, object $event)
{
switch ($eventName) {
case KernelEvents::REQUEST:
@@ -61,7 +61,7 @@ class TraceableEventDispatcher extends BaseTraceableEventDispatcher
/**
* {@inheritdoc}
*/
protected function afterDispatch(string $eventName, $event)
protected function afterDispatch(string $eventName, object $event)
{
switch ($eventName) {
case KernelEvents::CONTROLLER_ARGUMENTS:

View File

@@ -37,13 +37,15 @@ class AddAnnotatedClassesToCachePass implements CompilerPassInterface
*/
public function process(ContainerBuilder $container)
{
$annotatedClasses = $this->kernel->getAnnotatedClassesToCompile();
$annotatedClasses = [];
foreach ($container->getExtensions() as $extension) {
if ($extension instanceof Extension) {
$annotatedClasses = array_merge($annotatedClasses, $extension->getAnnotatedClassesToCompile());
$annotatedClasses[] = $extension->getAnnotatedClassesToCompile();
}
}
$annotatedClasses = array_merge($this->kernel->getAnnotatedClassesToCompile(), ...$annotatedClasses);
$existingClasses = $this->getClassesInComposerClassMaps();
$annotatedClasses = $container->getParameterBag()->resolveValue($annotatedClasses);

View File

@@ -34,6 +34,10 @@ class ControllerArgumentValueResolverPass implements CompilerPassInterface
public function __construct(string $argumentResolverService = 'argument_resolver', string $argumentValueResolverTag = 'controller.argument_value_resolver', string $traceableResolverStopwatch = 'debug.stopwatch')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->argumentResolverService = $argumentResolverService;
$this->argumentValueResolverTag = $argumentValueResolverTag;
$this->traceableResolverStopwatch = $traceableResolverStopwatch;

View File

@@ -25,7 +25,7 @@ abstract class Extension extends BaseExtension
/**
* Gets the annotated classes to cache.
*
* @return array An array of classes
* @return array
*/
public function getAnnotatedClassesToCompile()
{

View File

@@ -30,6 +30,10 @@ class FragmentRendererPass implements CompilerPassInterface
public function __construct(string $handlerService = 'fragment.handler', string $rendererTag = 'kernel.fragment_renderer')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->handlerService = $handlerService;
$this->rendererTag = $rendererTag;
}

View File

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

View File

@@ -23,6 +23,9 @@ class MergeExtensionConfigurationPass extends BaseMergeExtensionConfigurationPas
{
private $extensions;
/**
* @param string[] $extensions
*/
public function __construct(array $extensions)
{
$this->extensions = $extensions;

View File

@@ -12,6 +12,7 @@
namespace Symfony\Component\HttpKernel\DependencyInjection;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Attribute\Target;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
@@ -23,6 +24,8 @@ use Symfony\Component\DependencyInjection\LazyProxy\ProxyHelper;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\TypedReference;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
/**
* Creates the service-locators required by ServiceValueResolver.
@@ -38,6 +41,10 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
public function __construct(string $resolverServiceId = 'argument_resolver.service', string $controllerTag = 'controller.service_arguments', string $controllerLocator = 'argument_resolver.controller_locator', string $notTaggedControllerResolverServiceId = 'argument_resolver.not_tagged_controller')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->resolverServiceId = $resolverServiceId;
$this->controllerTag = $controllerTag;
$this->controllerLocator = $controllerLocator;
@@ -53,6 +60,13 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
$parameterBag = $container->getParameterBag();
$controllers = [];
$publicAliases = [];
foreach ($container->getAliases() as $id => $alias) {
if ($alias->isPublic() && !$alias->isPrivate()) {
$publicAliases[(string) $alias][] = $id;
}
}
foreach ($container->findTaggedServiceIds($this->controllerTag, true) as $id => $tags) {
$def = $container->getDefinition($id);
$def->setPublic(true);
@@ -136,7 +150,7 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
} elseif ($p->allowsNull() && !$p->isOptional()) {
$invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE;
}
} elseif (isset($bindings[$bindingName = $type.' $'.$p->name]) || isset($bindings[$bindingName = '$'.$p->name]) || isset($bindings[$bindingName = $type])) {
} elseif (isset($bindings[$bindingName = $type.' $'.$name = Target::parseName($p)]) || isset($bindings[$bindingName = '$'.$name]) || isset($bindings[$bindingName = $type])) {
$binding = $bindings[$bindingName];
[$bindingValue, $bindingId, , $bindingType, $bindingFile] = $binding->getValues();
@@ -161,7 +175,7 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
$invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE;
}
if (Request::class === $type) {
if (Request::class === $type || SessionInterface::class === $type || Response::class === $type) {
continue;
}
@@ -173,15 +187,22 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
$message .= ' Did you forget to add a use statement?';
}
throw new InvalidArgumentException($message);
}
$container->register($erroredId = '.errored.'.$container->hash($message), $type)
->addError($message);
$target = ltrim($target, '\\');
$args[$p->name] = $type ? new TypedReference($target, $type, $invalidBehavior, $p->name) : new Reference($target, $invalidBehavior);
$args[$p->name] = new Reference($erroredId, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE);
} else {
$target = ltrim($target, '\\');
$args[$p->name] = $type ? new TypedReference($target, $type, $invalidBehavior, Target::parseName($p)) : new Reference($target, $invalidBehavior);
}
}
// register the maps as a per-method service-locators
if ($args) {
$controllers[$id.'::'.$r->name] = ServiceLocatorTagPass::register($container, $args);
foreach ($publicAliases[$id] ?? [] as $alias) {
$controllers[$alias.'::'.$r->name] = clone $controllers[$id.'::'.$r->name];
}
}
}
}

View File

@@ -28,6 +28,10 @@ class RegisterLocaleAwareServicesPass implements CompilerPassInterface
public function __construct(string $listenerServiceId = 'locale_aware_listener', string $localeAwareTag = 'kernel.locale_aware')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->listenerServiceId = $listenerServiceId;
$this->localeAwareTag = $localeAwareTag;
}

View File

@@ -25,6 +25,10 @@ class RemoveEmptyControllerArgumentLocatorsPass implements CompilerPassInterface
public function __construct(string $controllerLocator = 'argument_resolver.controller_locator')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->controllerLocator = $controllerLocator;
}
@@ -43,6 +47,11 @@ class RemoveEmptyControllerArgumentLocatorsPass implements CompilerPassInterface
// any methods listed for call-at-instantiation cannot be actions
$reason = false;
[$id, $action] = explode('::', $controller);
if ($container->hasAlias($id)) {
continue;
}
$controllerDef = $container->getDefinition($id);
foreach ($controllerDef->getMethodCalls() as [$method]) {
if (0 === strcasecmp($action, $method)) {
@@ -51,7 +60,7 @@ class RemoveEmptyControllerArgumentLocatorsPass implements CompilerPassInterface
}
}
if (!$reason) {
// Deprecated since Symfony 4.1. See Symfony\Component\HttpKernel\Controller\ContainerControllerResolver
// see Symfony\Component\HttpKernel\Controller\ContainerControllerResolver
$controllers[$id.':'.$action] = $argumentRef;
if ('__invoke' === $action) {

View File

@@ -27,6 +27,10 @@ class ResettableServicePass implements CompilerPassInterface
public function __construct(string $tagName = 'kernel.reset')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->tagName = $tagName;
}
@@ -53,6 +57,10 @@ class ResettableServicePass implements CompilerPassInterface
$methods[$id] = [];
}
if ('ignore' === ($attributes['on_invalid'] ?? null)) {
$attributes['method'] = '?'.$attributes['method'];
}
$methods[$id][] = $attributes['method'];
}
}

View File

@@ -26,6 +26,10 @@ class ServicesResetter implements ResetInterface
private $resettableServices;
private $resetMethods;
/**
* @param \Traversable<string, object> $resettableServices
* @param array<string, string|string[]> $resetMethods
*/
public function __construct(\Traversable $resettableServices, array $resetMethods)
{
$this->resettableServices = $resettableServices;
@@ -36,6 +40,10 @@ class ServicesResetter implements ResetInterface
{
foreach ($this->resettableServices as $id => $service) {
foreach ((array) $this->resetMethods[$id] as $resetMethod) {
if ('?' === $resetMethod[0] && !method_exists($service, $resetMethod = substr($resetMethod, 1))) {
continue;
}
$service->$resetMethod();
}
}

View File

@@ -11,6 +11,9 @@
namespace Symfony\Component\HttpKernel\Event;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Allows filtering of controller arguments.
*
@@ -22,9 +25,37 @@ namespace Symfony\Component\HttpKernel\Event;
* controller.
*
* @author Christophe Coevoet <stof@notk.org>
*
* @final since Symfony 4.4
*/
class ControllerArgumentsEvent extends FilterControllerArgumentsEvent
final class ControllerArgumentsEvent extends KernelEvent
{
private $controller;
private $arguments;
public function __construct(HttpKernelInterface $kernel, callable $controller, array $arguments, Request $request, ?int $requestType)
{
parent::__construct($kernel, $request, $requestType);
$this->controller = $controller;
$this->arguments = $arguments;
}
public function getController(): callable
{
return $this->controller;
}
public function setController(callable $controller)
{
$this->controller = $controller;
}
public function getArguments(): array
{
return $this->arguments;
}
public function setArguments(array $arguments)
{
$this->arguments = $arguments;
}
}

View File

@@ -11,6 +11,9 @@
namespace Symfony\Component\HttpKernel\Event;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Allows filtering of a controller callable.
*
@@ -21,9 +24,25 @@ namespace Symfony\Component\HttpKernel\Event;
* Controllers should be callables.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @final since Symfony 4.4
*/
class ControllerEvent extends FilterControllerEvent
final class ControllerEvent extends KernelEvent
{
private $controller;
public function __construct(HttpKernelInterface $kernel, callable $controller, Request $request, ?int $requestType)
{
parent::__construct($kernel, $request, $requestType);
$this->setController($controller);
}
public function getController(): callable
{
return $this->controller;
}
public function setController(callable $controller): void
{
$this->controller = $controller;
}
}

View File

@@ -11,6 +11,9 @@
namespace Symfony\Component\HttpKernel\Event;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Allows to create a response for a thrown exception.
*
@@ -23,9 +26,51 @@ namespace Symfony\Component\HttpKernel\Event;
* event.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @final since Symfony 4.4
*/
class ExceptionEvent extends GetResponseForExceptionEvent
final class ExceptionEvent extends RequestEvent
{
private $throwable;
/**
* @var bool
*/
private $allowCustomResponseCode = false;
public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, \Throwable $e)
{
parent::__construct($kernel, $request, $requestType);
$this->setThrowable($e);
}
public function getThrowable(): \Throwable
{
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->throwable = $exception;
}
/**
* Mark the event as allowing a custom response code.
*/
public function allowCustomResponseCode(): void
{
$this->allowCustomResponseCode = true;
}
/**
* Returns true if the event allows a custom response code.
*/
public function isAllowingCustomResponseCode(): bool
{
return $this->allowCustomResponseCode;
}
}

View File

@@ -1,43 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Event;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* @deprecated since Symfony 4.3, use ControllerArgumentsEvent instead
*/
class FilterControllerArgumentsEvent extends FilterControllerEvent
{
private $arguments;
public function __construct(HttpKernelInterface $kernel, callable $controller, array $arguments, Request $request, ?int $requestType)
{
parent::__construct($kernel, $controller, $request, $requestType);
$this->arguments = $arguments;
}
/**
* @return array
*/
public function getArguments()
{
return $this->arguments;
}
public function setArguments(array $arguments)
{
$this->arguments = $arguments;
}
}

View File

@@ -1,45 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Event;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* @deprecated since Symfony 4.3, use ControllerEvent instead
*/
class FilterControllerEvent extends KernelEvent
{
private $controller;
public function __construct(HttpKernelInterface $kernel, callable $controller, Request $request, ?int $requestType)
{
parent::__construct($kernel, $request, $requestType);
$this->setController($controller);
}
/**
* Returns the current controller.
*
* @return callable
*/
public function getController()
{
return $this->controller;
}
public function setController(callable $controller)
{
$this->controller = $controller;
}
}

View File

@@ -1,49 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Event;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* @deprecated since Symfony 4.3, use ResponseEvent instead
*/
class FilterResponseEvent extends KernelEvent
{
private $response;
public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, Response $response)
{
parent::__construct($kernel, $request, $requestType);
$this->setResponse($response);
}
/**
* Returns the current response object.
*
* @return Response
*/
public function getResponse()
{
return $this->response;
}
/**
* Sets a new response object.
*/
public function setResponse(Response $response)
{
$this->response = $response;
}
}

View File

@@ -15,9 +15,7 @@ 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
final class FinishRequestEvent extends KernelEvent
{
}

View File

@@ -1,52 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Event;
use Symfony\Component\HttpFoundation\Response;
/**
* @deprecated since Symfony 4.3, use RequestEvent instead
*/
class GetResponseEvent extends KernelEvent
{
private $response;
/**
* Returns the response object.
*
* @return Response|null
*/
public function getResponse()
{
return $this->response;
}
/**
* Sets a response and stops event propagation.
*/
public function setResponse(Response $response)
{
$this->response = $response;
$this->stopPropagation();
}
/**
* Returns whether a response was set.
*
* @return bool Whether a response was set
*/
public function hasResponse()
{
return null !== $this->response;
}
}

View File

@@ -1,55 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Event;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* @deprecated since Symfony 4.3, use ViewEvent instead
*/
class GetResponseForControllerResultEvent extends RequestEvent
{
/**
* The return value of the controller.
*
* @var mixed
*/
private $controllerResult;
public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, $controllerResult)
{
parent::__construct($kernel, $request, $requestType);
$this->controllerResult = $controllerResult;
}
/**
* Returns the return value of the controller.
*
* @return mixed The controller return value
*/
public function getControllerResult()
{
return $this->controllerResult;
}
/**
* Assigns the return value of the controller.
*
* @param mixed $controllerResult The controller return value
*/
public function setControllerResult($controllerResult)
{
$this->controllerResult = $controllerResult;
}
}

View File

@@ -1,91 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Event;
use Symfony\Component\Debug\Exception\FatalThrowableError;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* @deprecated since Symfony 4.3, use ExceptionEvent instead
*/
class GetResponseForExceptionEvent extends RequestEvent
{
private $throwable;
private $exception;
private $allowCustomResponseCode = false;
public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, \Throwable $e)
{
parent::__construct($kernel, $request, $requestType);
$this->setThrowable($e);
}
public function getThrowable(): \Throwable
{
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)
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.4, use "setThrowable()" instead.', __METHOD__), \E_USER_DEPRECATED);
$this->throwable = $this->exception = $exception;
}
/**
* Mark the event as allowing a custom response code.
*/
public function allowCustomResponseCode()
{
$this->allowCustomResponseCode = true;
}
/**
* Returns true if the event allows a custom response code.
*
* @return bool
*/
public function isAllowingCustomResponseCode()
{
return $this->allowCustomResponseCode;
}
}

View File

@@ -11,9 +11,9 @@
namespace Symfony\Component\HttpKernel\Event;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Contracts\EventDispatcher\Event;
/**
* Base class for events thrown in the HttpKernel component.
@@ -28,7 +28,7 @@ class KernelEvent extends Event
/**
* @param int $requestType The request type the kernel is currently processing; one of
* HttpKernelInterface::MASTER_REQUEST or HttpKernelInterface::SUB_REQUEST
* HttpKernelInterface::MAIN_REQUEST or HttpKernelInterface::SUB_REQUEST
*/
public function __construct(HttpKernelInterface $kernel, Request $request, ?int $requestType)
{
@@ -60,7 +60,7 @@ class KernelEvent extends Event
/**
* Returns the request type the kernel is currently processing.
*
* @return int One of HttpKernelInterface::MASTER_REQUEST and
* @return int One of HttpKernelInterface::MAIN_REQUEST and
* HttpKernelInterface::SUB_REQUEST
*/
public function getRequestType()
@@ -68,13 +68,25 @@ class KernelEvent extends Event
return $this->requestType;
}
/**
* Checks if this is the main request.
*/
public function isMainRequest(): bool
{
return HttpKernelInterface::MAIN_REQUEST === $this->requestType;
}
/**
* Checks if this is a master request.
*
* @return bool True if the request is a master request
* @return bool
*
* @deprecated since symfony/http-kernel 5.3, use isMainRequest() instead
*/
public function isMasterRequest()
{
return HttpKernelInterface::MASTER_REQUEST === $this->requestType;
trigger_deprecation('symfony/http-kernel', '5.3', '"%s()" is deprecated, use "isMainRequest()" instead.', __METHOD__);
return $this->isMainRequest();
}
}

View File

@@ -1,41 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Event;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* @deprecated since Symfony 4.3, use TerminateEvent instead
*/
class PostResponseEvent extends KernelEvent
{
private $response;
public function __construct(HttpKernelInterface $kernel, Request $request, Response $response)
{
parent::__construct($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
$this->response = $response;
}
/**
* Returns the response for which this event was thrown.
*
* @return Response
*/
public function getResponse()
{
return $this->response;
}
}

View File

@@ -11,6 +11,8 @@
namespace Symfony\Component\HttpKernel\Event;
use Symfony\Component\HttpFoundation\Response;
/**
* Allows to create a response for a request.
*
@@ -20,6 +22,37 @@ namespace Symfony\Component\HttpKernel\Event;
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class RequestEvent extends GetResponseEvent
class RequestEvent extends KernelEvent
{
private $response;
/**
* Returns the response object.
*
* @return Response|null
*/
public function getResponse()
{
return $this->response;
}
/**
* Sets a response and stops event propagation.
*/
public function setResponse(Response $response)
{
$this->response = $response;
$this->stopPropagation();
}
/**
* Returns whether a response was set.
*
* @return bool
*/
public function hasResponse()
{
return null !== $this->response;
}
}

View File

@@ -11,6 +11,10 @@
namespace Symfony\Component\HttpKernel\Event;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Allows to filter a Response object.
*
@@ -19,9 +23,25 @@ namespace Symfony\Component\HttpKernel\Event;
* browser.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @final since Symfony 4.4
*/
class ResponseEvent extends FilterResponseEvent
final class ResponseEvent extends KernelEvent
{
private $response;
public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, Response $response)
{
parent::__construct($kernel, $request, $requestType);
$this->setResponse($response);
}
public function getResponse(): Response
{
return $this->response;
}
public function setResponse(Response $response): void
{
$this->response = $response;
}
}

View File

@@ -11,16 +11,31 @@
namespace Symfony\Component\HttpKernel\Event;
use Symfony\Component\HttpFoundation\Request;
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`.
* Since it's only triggered on main requests, the `getRequestType()` method
* will always return the value of `HttpKernelInterface::MAIN_REQUEST`.
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*
* @final since Symfony 4.4
*/
class TerminateEvent extends PostResponseEvent
final class TerminateEvent extends KernelEvent
{
private $response;
public function __construct(HttpKernelInterface $kernel, Request $request, Response $response)
{
parent::__construct($kernel, $request, HttpKernelInterface::MAIN_REQUEST);
$this->response = $response;
}
public function getResponse(): Response
{
return $this->response;
}
}

View File

@@ -11,6 +11,9 @@
namespace Symfony\Component\HttpKernel\Event;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Allows to create a response for the return value of a controller.
*
@@ -19,9 +22,40 @@ namespace Symfony\Component\HttpKernel\Event;
* response is set.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @final since Symfony 4.4
*/
class ViewEvent extends GetResponseForControllerResultEvent
final class ViewEvent extends RequestEvent
{
/**
* The return value of the controller.
*
* @var mixed
*/
private $controllerResult;
public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, $controllerResult)
{
parent::__construct($kernel, $request, $requestType);
$this->controllerResult = $controllerResult;
}
/**
* Returns the return value of the controller.
*
* @return mixed
*/
public function getControllerResult()
{
return $this->controllerResult;
}
/**
* Assigns the return value of the controller.
*
* @param mixed $controllerResult The controller return value
*/
public function setControllerResult($controllerResult): void
{
$this->controllerResult = $controllerResult;
}
}

View File

@@ -13,12 +13,16 @@ namespace Symfony\Component\HttpKernel\EventListener;
use Psr\Container\ContainerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpFoundation\Session\SessionUtils;
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\Exception\UnexpectedSessionUsageException;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Contracts\Service\ResetInterface;
/**
* Sets the session onto the request on the "kernel.request" event and saves
@@ -33,39 +37,65 @@ use Symfony\Component\HttpKernel\KernelEvents;
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
* @author Tobias Schultze <http://tobion.de>
*
* @internal since Symfony 4.3
* @internal
*/
abstract class AbstractSessionListener implements EventSubscriberInterface
abstract class AbstractSessionListener implements EventSubscriberInterface, ResetInterface
{
public const NO_AUTO_CACHE_CONTROL_HEADER = 'Symfony-Session-NoAutoCacheControl';
protected $container;
private $sessionUsageStack = [];
private $debug;
public function __construct(ContainerInterface $container = null)
/**
* @var array<string, mixed>
*/
private $sessionOptions;
public function __construct(ContainerInterface $container = null, bool $debug = false, array $sessionOptions = [])
{
$this->container = $container;
$this->debug = $debug;
$this->sessionOptions = $sessionOptions;
}
public function onKernelRequest(GetResponseEvent $event)
public function onKernelRequest(RequestEvent $event)
{
if (!$event->isMasterRequest()) {
if (!$event->isMainRequest()) {
return;
}
$request = $event->getRequest();
if (!$request->hasSession()) {
// This variable prevents calling `$this->getSession()` twice in case the Request (and the below factory) is cloned
$sess = null;
$request->setSessionFactory(function () use (&$sess) { return $sess ?? $sess = $this->getSession(); });
$request->setSessionFactory(function () use (&$sess, $request) {
if (!$sess) {
$sess = $this->getSession();
/*
* For supporting sessions in php runtime with runners like roadrunner or swoole, the session
* cookie needs to be read from the cookie bag and set on the session storage.
*
* Do not set it when a native php session is active.
*/
if ($sess && !$sess->isStarted() && \PHP_SESSION_ACTIVE !== session_status()) {
$sessionId = $sess->getId() ?: $request->cookies->get($sess->getName(), '');
$sess->setId($sessionId);
}
}
return $sess;
});
}
$session = $this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : null;
$this->sessionUsageStack[] = $session instanceof Session ? $session->getUsageIndex() : 0;
}
public function onKernelResponse(FilterResponseEvent $event)
public function onKernelResponse(ResponseEvent $event)
{
if (!$event->isMasterRequest()) {
if (!$event->isMainRequest() || (!$this->container->has('initialized_session') && !$event->getRequest()->hasSession())) {
return;
}
@@ -78,16 +108,6 @@ abstract class AbstractSessionListener implements EventSubscriberInterface
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');
}
}
if ($session->isStarted()) {
/*
* Saves the session, in case it is still open, before sending the response/headers.
@@ -115,20 +135,135 @@ abstract class AbstractSessionListener implements EventSubscriberInterface
* it is saved will just restart it.
*/
$session->save();
/*
* For supporting sessions in php runtime with runners like roadrunner or swoole the session
* cookie need to be written on the response object and should not be written by PHP itself.
*/
$sessionName = $session->getName();
$sessionId = $session->getId();
$sessionOptions = $this->getSessionOptions($this->sessionOptions);
$sessionCookiePath = $sessionOptions['cookie_path'] ?? '/';
$sessionCookieDomain = $sessionOptions['cookie_domain'] ?? null;
$sessionCookieSecure = $sessionOptions['cookie_secure'] ?? false;
$sessionCookieHttpOnly = $sessionOptions['cookie_httponly'] ?? true;
$sessionCookieSameSite = $sessionOptions['cookie_samesite'] ?? Cookie::SAMESITE_LAX;
$sessionUseCookies = $sessionOptions['use_cookies'] ?? true;
SessionUtils::popSessionCookie($sessionName, $sessionId);
if ($sessionUseCookies) {
$request = $event->getRequest();
$requestSessionCookieId = $request->cookies->get($sessionName);
$isSessionEmpty = $session->isEmpty() && empty($_SESSION); // checking $_SESSION to keep compatibility with native sessions
if ($requestSessionCookieId && $isSessionEmpty) {
// PHP internally sets the session cookie value to "deleted" when setcookie() is called with empty string $value argument
// which happens in \Symfony\Component\HttpFoundation\Session\Storage\Handler\AbstractSessionHandler::destroy
// when the session gets invalidated (for example on logout) so we must handle this case here too
// otherwise we would send two Set-Cookie headers back with the response
SessionUtils::popSessionCookie($sessionName, 'deleted');
$response->headers->clearCookie(
$sessionName,
$sessionCookiePath,
$sessionCookieDomain,
$sessionCookieSecure,
$sessionCookieHttpOnly,
$sessionCookieSameSite
);
} elseif ($sessionId !== $requestSessionCookieId && !$isSessionEmpty) {
$expire = 0;
$lifetime = $sessionOptions['cookie_lifetime'] ?? null;
if ($lifetime) {
$expire = time() + $lifetime;
}
$response->headers->setCookie(
Cookie::create(
$sessionName,
$sessionId,
$expire,
$sessionCookiePath,
$sessionCookieDomain,
$sessionCookieSecure,
$sessionCookieHttpOnly,
false,
$sessionCookieSameSite
)
);
}
}
}
if ($session instanceof Session ? $session->getUsageIndex() === end($this->sessionUsageStack) : !$session->isStarted()) {
return;
}
if ($autoCacheControl) {
$maxAge = $response->headers->hasCacheControlDirective('public') ? 0 : (int) $response->getMaxAge();
$response
->setExpires(new \DateTimeImmutable('+'.$maxAge.' seconds'))
->setPrivate()
->setMaxAge($maxAge)
->headers->addCacheControlDirective('must-revalidate');
}
if (!$event->getRequest()->attributes->get('_stateless', false)) {
return;
}
if ($this->debug) {
throw new UnexpectedSessionUsageException('Session was used while the request was declared stateless.');
}
if ($this->container->has('logger')) {
$this->container->get('logger')->warning('Session was used while the request was declared stateless.');
}
}
/**
* @internal
*/
public function onFinishRequest(FinishRequestEvent $event)
{
if ($event->isMasterRequest()) {
if ($event->isMainRequest()) {
array_pop($this->sessionUsageStack);
}
}
public static function getSubscribedEvents()
public function onSessionUsage(): void
{
if (!$this->debug) {
return;
}
if ($this->container && $this->container->has('session_collector')) {
$this->container->get('session_collector')();
}
if (!$requestStack = $this->container && $this->container->has('request_stack') ? $this->container->get('request_stack') : null) {
return;
}
$stateless = false;
$clonedRequestStack = clone $requestStack;
while (null !== ($request = $clonedRequestStack->pop()) && !$stateless) {
$stateless = $request->attributes->get('_stateless');
}
if (!$stateless) {
return;
}
if (!$session = $this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : $requestStack->getCurrentRequest()->getSession()) {
return;
}
if ($session->isStarted()) {
$session->save();
}
throw new UnexpectedSessionUsageException('Session was used while the request was declared stateless.');
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => ['onKernelRequest', 128],
@@ -138,10 +273,43 @@ abstract class AbstractSessionListener implements EventSubscriberInterface
];
}
public function reset(): void
{
if (\PHP_SESSION_ACTIVE === session_status()) {
session_abort();
}
session_unset();
$_SESSION = [];
if (!headers_sent()) { // session id can only be reset when no headers were so we check for headers_sent first
session_id('');
}
}
/**
* Gets the session object.
*
* @return SessionInterface|null A SessionInterface instance or null if no session is available
* @return SessionInterface|null
*/
abstract protected function getSession();
private function getSessionOptions(array $sessionOptions): array
{
$mergedSessionOptions = [];
foreach (session_get_cookie_params() as $key => $value) {
$mergedSessionOptions['cookie_'.$key] = $value;
}
foreach ($sessionOptions as $key => $value) {
// do the same logic as in the NativeSessionStorage
if ('cookie_secure' === $key && 'auto' === $value) {
continue;
}
$mergedSessionOptions[$key] = $value;
}
return $mergedSessionOptions;
}
}

View File

@@ -15,10 +15,12 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
trigger_deprecation('symfony/http-kernel', '5.4', '"%s" is deprecated use "%s" instead.', AbstractTestSessionListener::class, AbstractSessionListener::class);
/**
* TestSessionListener.
*
@@ -27,7 +29,9 @@ use Symfony\Component\HttpKernel\KernelEvents;
* @author Bulat Shakirzyanov <mallluhuct@gmail.com>
* @author Fabien Potencier <fabien@symfony.com>
*
* @internal since Symfony 4.3
* @internal
*
* @deprecated since Symfony 5.4, use AbstractSessionListener instead
*/
abstract class AbstractTestSessionListener implements EventSubscriberInterface
{
@@ -39,14 +43,16 @@ abstract class AbstractTestSessionListener implements EventSubscriberInterface
$this->sessionOptions = $sessionOptions;
}
public function onKernelRequest(GetResponseEvent $event)
public function onKernelRequest(RequestEvent $event)
{
if (!$event->isMasterRequest()) {
if (!$event->isMainRequest()) {
return;
}
// bootstrap the session
if (!$session = $this->getSession()) {
if ($event->getRequest()->hasSession()) {
$session = $event->getRequest()->getSession();
} elseif (!$session = $this->getSession()) {
return;
}
@@ -59,12 +65,12 @@ abstract class AbstractTestSessionListener implements EventSubscriberInterface
}
/**
* Checks if session was initialized and saves if current request is master
* Checks if session was initialized and saves if current request is the main request
* Runs on 'kernel.response' in test environment.
*/
public function onKernelResponse(FilterResponseEvent $event)
public function onKernelResponse(ResponseEvent $event)
{
if (!$event->isMasterRequest()) {
if (!$event->isMainRequest()) {
return;
}
@@ -97,10 +103,10 @@ abstract class AbstractTestSessionListener implements EventSubscriberInterface
}
}
public static function getSubscribedEvents()
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => ['onKernelRequest', 192],
KernelEvents::REQUEST => ['onKernelRequest', 127], // AFTER SessionListener
KernelEvents::RESPONSE => ['onKernelResponse', -128],
];
}
@@ -108,7 +114,7 @@ abstract class AbstractTestSessionListener implements EventSubscriberInterface
/**
* Gets the session object.
*
* @return SessionInterface|null A SessionInterface instance or null if no session is available
* @return SessionInterface|null
*/
abstract protected function getSession();
}

View File

@@ -12,7 +12,7 @@
namespace Symfony\Component\HttpKernel\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
@@ -20,7 +20,7 @@ use Symfony\Component\HttpKernel\KernelEvents;
*
* @author Gildas Quemener <gildas.quemener@gmail.com>
*
* @final since Symfony 4.3
* @final
*/
class AddRequestFormatsListener implements EventSubscriberInterface
{
@@ -34,7 +34,7 @@ class AddRequestFormatsListener implements EventSubscriberInterface
/**
* Adds request formats.
*/
public function onKernelRequest(GetResponseEvent $event)
public function onKernelRequest(RequestEvent $event)
{
$request = $event->getRequest();
foreach ($this->formats as $format => $mimeTypes) {
@@ -45,7 +45,7 @@ class AddRequestFormatsListener implements EventSubscriberInterface
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents()
public static function getSubscribedEvents(): array
{
return [KernelEvents::REQUEST => ['onKernelRequest', 100]];
}

View File

@@ -15,12 +15,8 @@ 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 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;
@@ -29,31 +25,38 @@ use Symfony\Component\HttpKernel\KernelEvents;
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
* @final
*
* @internal since Symfony 5.3
*/
class DebugHandlersListener implements EventSubscriberInterface
{
private $earlyHandler;
private $exceptionHandler;
private $logger;
private $deprecationLogger;
private $levels;
private $throwAt;
private $scream;
private $fileLinkFormat;
private $scope;
private $firstCall = true;
private $hasTerminatedWithException;
/**
* @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
* @param callable|null $exceptionHandler A handler that must support \Throwable instances that will be called on Exception
* @param array|int|null $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 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, $scope = true, $deprecationLogger = null, $fileLinkFormat = null)
{
if (!\is_bool($scope)) {
trigger_deprecation('symfony/http-kernel', '5.4', 'Passing a $fileLinkFormat is deprecated.');
$scope = $deprecationLogger;
$deprecationLogger = $fileLinkFormat;
}
$handler = set_exception_handler('is_int');
$this->earlyHandler = \is_array($handler) ? $handler[0] : null;
restore_exception_handler();
@@ -63,19 +66,19 @@ class DebugHandlersListener implements EventSubscriberInterface
$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;
$this->deprecationLogger = $deprecationLogger;
}
/**
* Configures the error handler.
*/
public function configure(Event $event = null)
public function configure(object $event = null)
{
if ($event instanceof ConsoleEvent && !\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
return;
}
if (!$event instanceof KernelEvent ? !$this->firstCall : !$event->isMasterRequest()) {
if (!$event instanceof KernelEvent ? !$this->firstCall : !$event->isMainRequest()) {
return;
}
$this->firstCall = $this->hasTerminatedWithException = false;
@@ -84,35 +87,34 @@ class DebugHandlersListener implements EventSubscriberInterface
$handler = \is_array($handler) ? $handler[0] : null;
restore_exception_handler();
if (!$handler instanceof ErrorHandler && !$handler instanceof LegacyErrorHandler) {
if (!$handler instanceof ErrorHandler) {
$handler = $this->earlyHandler;
}
if ($this->logger || null !== $this->throwAt) {
if ($handler instanceof ErrorHandler || $handler instanceof LegacyErrorHandler) {
if ($this->logger) {
$handler->setDefaultLogger($this->logger, $this->levels);
if (\is_array($this->levels)) {
$levels = 0;
foreach ($this->levels as $type => $log) {
$levels |= $type;
}
} else {
$levels = $this->levels;
if ($handler instanceof ErrorHandler) {
if ($this->logger || $this->deprecationLogger) {
$this->setDefaultLoggers($handler);
if (\is_array($this->levels)) {
$levels = 0;
foreach ($this->levels as $type => $log) {
$levels |= $type;
}
if ($this->scream) {
$handler->screamAt($levels);
}
if ($this->scope) {
$handler->scopeAt($levels & ~\E_USER_DEPRECATED & ~\E_DEPRECATED);
} else {
$handler->scopeAt(0, true);
}
$this->logger = $this->levels = null;
} else {
$levels = $this->levels;
}
if (null !== $this->throwAt) {
$handler->throwAt($this->throwAt, true);
if ($this->scream) {
$handler->screamAt($levels);
}
if ($this->scope) {
$handler->scopeAt($levels & ~\E_USER_DEPRECATED & ~\E_DEPRECATED);
} else {
$handler->scopeAt(0, true);
}
$this->logger = $this->deprecationLogger = $this->levels = null;
}
if (null !== $this->throwAt) {
$handler->throwAt($this->throwAt, true);
}
}
if (!$this->exceptionHandler) {
@@ -135,27 +137,47 @@ class DebugHandlersListener implements EventSubscriberInterface
$output = $output->getErrorOutput();
}
$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);
}
$app->renderThrowable($e, $output);
};
}
}
if ($this->exceptionHandler) {
if ($handler instanceof ErrorHandler || $handler instanceof LegacyErrorHandler) {
if ($handler instanceof ErrorHandler) {
$handler->setExceptionHandler($this->exceptionHandler);
}
$this->exceptionHandler = null;
}
}
public static function getSubscribedEvents()
private function setDefaultLoggers(ErrorHandler $handler): void
{
if (\is_array($this->levels)) {
$levelsDeprecatedOnly = [];
$levelsWithoutDeprecated = [];
foreach ($this->levels as $type => $log) {
if (\E_DEPRECATED == $type || \E_USER_DEPRECATED == $type) {
$levelsDeprecatedOnly[$type] = $log;
} else {
$levelsWithoutDeprecated[$type] = $log;
}
}
} else {
$levelsDeprecatedOnly = $this->levels & (\E_DEPRECATED | \E_USER_DEPRECATED);
$levelsWithoutDeprecated = $this->levels & ~\E_DEPRECATED & ~\E_USER_DEPRECATED;
}
$defaultLoggerLevels = $this->levels;
if ($this->deprecationLogger && $levelsDeprecatedOnly) {
$handler->setDefaultLogger($this->deprecationLogger, $levelsDeprecatedOnly);
$defaultLoggerLevels = $levelsWithoutDeprecated;
}
if ($this->logger && $defaultLoggerLevels) {
$handler->setDefaultLogger($this->logger, $defaultLoggerLevels);
}
}
public static function getSubscribedEvents(): array
{
$events = [KernelEvents::REQUEST => ['configure', 2048]];

View File

@@ -14,11 +14,12 @@ 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\Event\ResponseEvent;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
@@ -32,29 +33,59 @@ class ErrorListener implements EventSubscriberInterface
protected $controller;
protected $logger;
protected $debug;
/**
* @var array<class-string, array{log_level: string|null, status_code: int<100,599>|null}>
*/
protected $exceptionsMapping;
public function __construct($controller, LoggerInterface $logger = null, $debug = false)
/**
* @param array<class-string, array{log_level: string|null, status_code: int<100,599>|null}> $exceptionsMapping
*/
public function __construct($controller, LoggerInterface $logger = null, bool $debug = false, array $exceptionsMapping = [])
{
$this->controller = $controller;
$this->logger = $logger;
$this->debug = $debug;
$this->exceptionsMapping = $exceptionsMapping;
}
public function logKernelException(ExceptionEvent $event)
{
$e = FlattenException::createFromThrowable($event->getThrowable());
$throwable = $event->getThrowable();
$logLevel = null;
$this->logException($event->getThrowable(), sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', $e->getClass(), $e->getMessage(), $e->getFile(), $e->getLine()));
foreach ($this->exceptionsMapping as $class => $config) {
if ($throwable instanceof $class && $config['log_level']) {
$logLevel = $config['log_level'];
break;
}
}
foreach ($this->exceptionsMapping as $class => $config) {
if (!$throwable instanceof $class || !$config['status_code']) {
continue;
}
if (!$throwable instanceof HttpExceptionInterface || $throwable->getStatusCode() !== $config['status_code']) {
$headers = $throwable instanceof HttpExceptionInterface ? $throwable->getHeaders() : [];
$throwable = new HttpException($config['status_code'], $throwable->getMessage(), $throwable, $headers);
$event->setThrowable($throwable);
}
break;
}
$e = FlattenException::createFromThrowable($throwable);
$this->logException($throwable, sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', $e->getClass(), $e->getMessage(), $e->getFile(), $e->getLine()), $logLevel);
}
public function onKernelException(ExceptionEvent $event, string $eventName = null, EventDispatcherInterface $eventDispatcher = null)
public function onKernelException(ExceptionEvent $event)
{
if (null === $this->controller) {
return;
}
$exception = $event->getThrowable();
$request = $this->duplicateRequest($exception, $event->getRequest());
$throwable = $event->getThrowable();
$request = $this->duplicateRequest($throwable, $event->getRequest());
try {
$response = $event->getKernel()->handle($request, HttpKernelInterface::SUB_REQUEST, false);
@@ -65,26 +96,29 @@ class ErrorListener implements EventSubscriberInterface
$prev = $e;
do {
if ($exception === $wrapper = $prev) {
if ($throwable === $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);
$prev->setValue($wrapper, $throwable);
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);
if ($this->debug) {
$event->getRequest()->attributes->set('_remove_csp_headers', true);
}
}
public function removeCspHeader(ResponseEvent $event): void
{
if ($this->debug && $event->getRequest()->attributes->get('_remove_csp_headers', false)) {
$event->getResponse()->headers->remove('Content-Security-Policy');
}
}
@@ -114,16 +148,19 @@ class ErrorListener implements EventSubscriberInterface
['logKernelException', 0],
['onKernelException', -128],
],
KernelEvents::RESPONSE => ['removeCspHeader', -128],
];
}
/**
* Logs an exception.
*/
protected function logException(\Throwable $exception, string $message): void
protected function logException(\Throwable $exception, string $message, string $logLevel = null): void
{
if (null !== $this->logger) {
if (!$exception instanceof HttpExceptionInterface || $exception->getStatusCode() >= 500) {
if (null !== $logLevel) {
$this->logger->log($logLevel, $message, ['exception' => $exception]);
} elseif (!$exception instanceof HttpExceptionInterface || $exception->getStatusCode() >= 500) {
$this->logger->critical($message, ['exception' => $exception]);
} else {
$this->logger->error($message, ['exception' => $exception]);

View File

@@ -1,136 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\EventListener;
use Psr\Log\LoggerInterface;
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\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);
/**
* @deprecated since Symfony 4.4, use ErrorListener instead
*/
class ExceptionListener 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(GetResponseForExceptionEvent $event)
{
$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()));
}
public function onKernelException(GetResponseForExceptionEvent $event)
{
if (null === $this->controller) {
return;
}
$exception = $event->getException();
$request = $this->duplicateRequest($exception, $event->getRequest());
$eventDispatcher = \func_num_args() > 2 ? func_get_arg(2) : null;
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 static function getSubscribedEvents()
{
return [
KernelEvents::EXCEPTION => [
['logKernelException', 0],
['onKernelException', -128],
],
];
}
/**
* Logs an exception.
*
* @param \Exception $exception The \Exception instance
* @param string $message The error message to log
*/
protected function logException(\Exception $exception, $message)
{
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.
*
* @return Request The cloned request
*/
protected function duplicateRequest(\Exception $exception, Request $request)
{
$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');
return $request;
}
}

View File

@@ -13,7 +13,7 @@ namespace Symfony\Component\HttpKernel\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\UriSigner;
@@ -29,7 +29,7 @@ use Symfony\Component\HttpKernel\UriSigner;
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.3
* @final
*/
class FragmentListener implements EventSubscriberInterface
{
@@ -50,7 +50,7 @@ class FragmentListener implements EventSubscriberInterface
*
* @throws AccessDeniedHttpException if the request does not come from a trusted IP
*/
public function onKernelRequest(GetResponseEvent $event)
public function onKernelRequest(RequestEvent $event)
{
$request = $event->getRequest();
@@ -65,7 +65,7 @@ class FragmentListener implements EventSubscriberInterface
return;
}
if ($event->isMasterRequest()) {
if ($event->isMainRequest()) {
$this->validateRequest($request);
}
@@ -83,15 +83,14 @@ class FragmentListener implements EventSubscriberInterface
}
// is the Request signed?
// we cannot use $request->getUri() here as we want to work with the original URI (no query string reordering)
if ($this->signer->check($request->getSchemeAndHttpHost().$request->getBaseUrl().$request->getPathInfo().(null !== ($qs = $request->server->get('QUERY_STRING')) ? '?'.$qs : ''))) {
if ($this->signer->checkRequest($request)) {
return;
}
throw new AccessDeniedHttpException();
}
public static function getSubscribedEvents()
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => [['onKernelRequest', 48]],

View File

@@ -29,7 +29,7 @@ class LocaleAwareListener implements EventSubscriberInterface
private $requestStack;
/**
* @param LocaleAwareInterface[] $localeAwareServices
* @param iterable<mixed, LocaleAwareInterface> $localeAwareServices
*/
public function __construct(iterable $localeAwareServices, RequestStack $requestStack)
{

View File

@@ -15,8 +15,8 @@ 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\Event\KernelEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\RequestContextAwareInterface;
@@ -25,19 +25,23 @@ use Symfony\Component\Routing\RequestContextAwareInterface;
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.3
* @final
*/
class LocaleListener implements EventSubscriberInterface
{
private $router;
private $defaultLocale;
private $requestStack;
private $useAcceptLanguageHeader;
private $enabledLocales;
public function __construct(RequestStack $requestStack, string $defaultLocale = 'en', RequestContextAwareInterface $router = null)
public function __construct(RequestStack $requestStack, string $defaultLocale = 'en', RequestContextAwareInterface $router = null, bool $useAcceptLanguageHeader = false, array $enabledLocales = [])
{
$this->defaultLocale = $defaultLocale;
$this->requestStack = $requestStack;
$this->router = $router;
$this->useAcceptLanguageHeader = $useAcceptLanguageHeader;
$this->enabledLocales = $enabledLocales;
}
public function setDefaultLocale(KernelEvent $event)
@@ -45,7 +49,7 @@ class LocaleListener implements EventSubscriberInterface
$event->getRequest()->setDefaultLocale($this->defaultLocale);
}
public function onKernelRequest(GetResponseEvent $event)
public function onKernelRequest(RequestEvent $event)
{
$request = $event->getRequest();
@@ -64,6 +68,9 @@ class LocaleListener implements EventSubscriberInterface
{
if ($locale = $request->attributes->get('_locale')) {
$request->setLocale($locale);
} elseif ($this->useAcceptLanguageHeader && $this->enabledLocales && ($preferredLanguage = $request->getPreferredLanguage($this->enabledLocales))) {
$request->setLocale($preferredLanguage);
$request->attributes->set('_vary_by_language', true);
}
}
@@ -74,7 +81,7 @@ class LocaleListener implements EventSubscriberInterface
}
}
public static function getSubscribedEvents()
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => [

View File

@@ -16,10 +16,11 @@ 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;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\Event\TerminateEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Profiler\Profile;
use Symfony\Component\HttpKernel\Profiler\Profiler;
/**
@@ -27,40 +28,44 @@ use Symfony\Component\HttpKernel\Profiler\Profiler;
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.3
* @final
*/
class ProfilerListener implements EventSubscriberInterface
{
protected $profiler;
protected $matcher;
protected $onlyException;
protected $onlyMasterRequests;
protected $onlyMainRequests;
protected $exception;
/** @var \SplObjectStorage<Request, Profile> */
protected $profiles;
protected $requestStack;
protected $collectParameter;
/** @var \SplObjectStorage<Request, Request|null> */
protected $parents;
/**
* @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 $onlyMainRequests True if the profiler only collects data when the request is the main request, false otherwise
*/
public function __construct(Profiler $profiler, RequestStack $requestStack, RequestMatcherInterface $matcher = null, bool $onlyException = false, bool $onlyMasterRequests = false)
public function __construct(Profiler $profiler, RequestStack $requestStack, RequestMatcherInterface $matcher = null, bool $onlyException = false, bool $onlyMainRequests = false, string $collectParameter = null)
{
$this->profiler = $profiler;
$this->matcher = $matcher;
$this->onlyException = $onlyException;
$this->onlyMasterRequests = $onlyMasterRequests;
$this->onlyMainRequests = $onlyMainRequests;
$this->profiles = new \SplObjectStorage();
$this->parents = new \SplObjectStorage();
$this->requestStack = $requestStack;
$this->collectParameter = $collectParameter;
}
/**
* Handles the onKernelException event.
*/
public function onKernelException(GetResponseForExceptionEvent $event)
public function onKernelException(ExceptionEvent $event)
{
if ($this->onlyMasterRequests && !$event->isMasterRequest()) {
if ($this->onlyMainRequests && !$event->isMainRequest()) {
return;
}
@@ -70,10 +75,9 @@ class ProfilerListener implements EventSubscriberInterface
/**
* Handles the onKernelResponse event.
*/
public function onKernelResponse(FilterResponseEvent $event)
public function onKernelResponse(ResponseEvent $event)
{
$master = $event->isMasterRequest();
if ($this->onlyMasterRequests && !$master) {
if ($this->onlyMainRequests && !$event->isMainRequest()) {
return;
}
@@ -82,6 +86,10 @@ class ProfilerListener implements EventSubscriberInterface
}
$request = $event->getRequest();
if (null !== $this->collectParameter && null !== $collectParameterValue = $request->get($this->collectParameter)) {
true === $collectParameterValue || filter_var($collectParameterValue, \FILTER_VALIDATE_BOOLEAN) ? $this->profiler->enable() : $this->profiler->disable();
}
$exception = $this->exception;
$this->exception = null;
@@ -89,7 +97,7 @@ class ProfilerListener implements EventSubscriberInterface
return;
}
$session = method_exists(Request::class, 'getPreferredFormat') && $request->hasPreviousSession() && $request->hasSession() ? $request->getSession() : null;
$session = $request->hasPreviousSession() && $request->hasSession() ? $request->getSession() : null;
if ($session instanceof Session) {
$usageIndexValue = $usageIndexReference = &$session->getUsageIndex();
@@ -111,7 +119,7 @@ class ProfilerListener implements EventSubscriberInterface
$this->parents[$request] = $this->requestStack->getParentRequest();
}
public function onKernelTerminate(PostResponseEvent $event)
public function onKernelTerminate(TerminateEvent $event)
{
// attach children to parents
foreach ($this->profiles as $request) {
@@ -131,7 +139,7 @@ class ProfilerListener implements EventSubscriberInterface
$this->parents = new \SplObjectStorage();
}
public static function getSubscribedEvents()
public static function getSubscribedEvents(): array
{
return [
KernelEvents::RESPONSE => ['onKernelResponse', -100],

View File

@@ -12,7 +12,7 @@
namespace Symfony\Component\HttpKernel\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
@@ -20,23 +20,25 @@ use Symfony\Component\HttpKernel\KernelEvents;
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.3
* @final
*/
class ResponseListener implements EventSubscriberInterface
{
private $charset;
private $addContentLanguageHeader;
public function __construct(string $charset)
public function __construct(string $charset, bool $addContentLanguageHeader = false)
{
$this->charset = $charset;
$this->addContentLanguageHeader = $addContentLanguageHeader;
}
/**
* Filters the Response.
*/
public function onKernelResponse(FilterResponseEvent $event)
public function onKernelResponse(ResponseEvent $event)
{
if (!$event->isMasterRequest()) {
if (!$event->isMainRequest()) {
return;
}
@@ -46,10 +48,18 @@ class ResponseListener implements EventSubscriberInterface
$response->setCharset($this->charset);
}
if ($this->addContentLanguageHeader && !$response->isInformational() && !$response->isEmpty() && !$response->headers->has('Content-Language')) {
$response->headers->set('Content-Language', $event->getRequest()->getLocale());
}
if ($event->getRequest()->attributes->get('_vary_by_language')) {
$response->setVary('Accept-Language', false);
}
$response->prepare($event->getRequest());
}
public static function getSubscribedEvents()
public static function getSubscribedEvents(): array
{
return [
KernelEvents::RESPONSE => 'onKernelResponse',

View File

@@ -16,9 +16,9 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -38,7 +38,7 @@ use Symfony\Component\Routing\RequestContextAwareInterface;
* @author Fabien Potencier <fabien@symfony.com>
* @author Yonel Ceruto <yonelceruto@gmail.com>
*
* @final since Symfony 4.3
* @final
*/
class RouterListener implements EventSubscriberInterface
{
@@ -50,9 +50,8 @@ class RouterListener implements EventSubscriberInterface
private $debug;
/**
* @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 UrlMatcherInterface|RequestMatcherInterface $matcher The Url or Request matcher
* @param RequestContext|null $context The RequestContext (can be null when $matcher implements RequestContextAwareInterface)
*
* @throws \InvalidArgumentException
*/
@@ -67,7 +66,7 @@ class RouterListener implements EventSubscriberInterface
}
$this->matcher = $matcher;
$this->context = $context ?: $matcher->getContext();
$this->context = $context ?? $matcher->getContext();
$this->requestStack = $requestStack;
$this->logger = $logger;
$this->projectDir = $projectDir;
@@ -94,7 +93,7 @@ class RouterListener implements EventSubscriberInterface
$this->setCurrentRequest($this->requestStack->getParentRequest());
}
public function onKernelRequest(GetResponseEvent $event)
public function onKernelRequest(RequestEvent $event)
{
$request = $event->getRequest();
@@ -127,7 +126,7 @@ class RouterListener implements EventSubscriberInterface
unset($parameters['_route'], $parameters['_controller']);
$request->attributes->set('_route_params', $parameters);
} catch (ResourceNotFoundException $e) {
$message = sprintf('No route found for "%s %s"', $request->getMethod(), $request->getPathInfo());
$message = sprintf('No route found for "%s %s"', $request->getMethod(), $request->getUriForPath($request->getPathInfo()));
if ($referer = $request->headers->get('referer')) {
$message .= sprintf(' (from "%s")', $referer);
@@ -135,13 +134,13 @@ class RouterListener implements EventSubscriberInterface
throw new NotFoundHttpException($message, $e);
} catch (MethodNotAllowedException $e) {
$message = sprintf('No route found for "%s %s": Method Not Allowed (Allow: %s)', $request->getMethod(), $request->getPathInfo(), implode(', ', $e->getAllowedMethods()));
$message = sprintf('No route found for "%s %s": Method Not Allowed (Allow: %s)', $request->getMethod(), $request->getUriForPath($request->getPathInfo()), implode(', ', $e->getAllowedMethods()));
throw new MethodNotAllowedHttpException($e->getAllowedMethods(), $message, $e);
}
}
public function onKernelException(GetResponseForExceptionEvent $event)
public function onKernelException(ExceptionEvent $event)
{
if (!$this->debug || !($e = $event->getThrowable()) instanceof NotFoundHttpException) {
return;
@@ -152,7 +151,7 @@ class RouterListener implements EventSubscriberInterface
}
}
public static function getSubscribedEvents()
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => [['onKernelRequest', 32]],

View File

@@ -1,46 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\EventListener;
@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;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* @author Tobias Schultze <http://tobion.de>
*
* @deprecated since Symfony 4.1, use AbstractSessionListener instead
*/
class SaveSessionListener implements EventSubscriberInterface
{
public function onKernelResponse(FilterResponseEvent $event)
{
if (!$event->isMasterRequest()) {
return;
}
$request = $event->getRequest();
if ($request->hasSession() && ($session = $request->getSession())->isStarted()) {
$session->save();
}
}
public static function getSubscribedEvents()
{
return [
// low priority but higher than StreamedResponseListener
KernelEvents::RESPONSE => [['onKernelResponse', -1000]],
];
}
}

View File

@@ -11,17 +11,16 @@
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;
use Symfony\Component\HttpKernel\Event\RequestEvent;
/**
* Sets the session in the request.
*
* When the passed container contains a "session_storage" entry which
* holds a NativeSessionStorage instance, the "cookie_secure" option
* will be set to true whenever the current master request is secure.
* will be set to true whenever the current main request is secure.
*
* @author Fabien Potencier <fabien@symfony.com>
*
@@ -29,23 +28,18 @@ use Symfony\Component\HttpKernel\Event\GetResponseEvent;
*/
class SessionListener extends AbstractSessionListener
{
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function onKernelRequest(GetResponseEvent $event)
public function onKernelRequest(RequestEvent $event)
{
parent::onKernelRequest($event);
if (!$event->isMasterRequest() || !$this->container->has('session')) {
if (!$event->isMainRequest() || (!$this->container->has('session') && !$this->container->has('session_factory'))) {
return;
}
if ($this->container->has('session_storage')
&& ($storage = $this->container->get('session_storage')) instanceof NativeSessionStorage
&& ($masterRequest = $this->container->get('request_stack')->getMasterRequest())
&& $masterRequest->isSecure()
&& ($mainRequest = $this->container->get('request_stack')->getMainRequest())
&& $mainRequest->isSecure()
) {
$storage->setOptions(['cookie_secure' => true]);
}
@@ -53,10 +47,14 @@ class SessionListener extends AbstractSessionListener
protected function getSession(): ?SessionInterface
{
if (!$this->container->has('session')) {
return null;
if ($this->container->has('session')) {
return $this->container->get('session');
}
return $this->container->get('session');
if ($this->container->has('session_factory')) {
return $this->container->get('session_factory')->createSession();
}
return null;
}
}

View File

@@ -13,7 +13,7 @@ namespace Symfony\Component\HttpKernel\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
@@ -22,16 +22,16 @@ use Symfony\Component\HttpKernel\KernelEvents;
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.3
* @final
*/
class StreamedResponseListener implements EventSubscriberInterface
{
/**
* Filters the Response.
*/
public function onKernelResponse(FilterResponseEvent $event)
public function onKernelResponse(ResponseEvent $event)
{
if (!$event->isMasterRequest()) {
if (!$event->isMainRequest()) {
return;
}
@@ -42,7 +42,7 @@ class StreamedResponseListener implements EventSubscriberInterface
}
}
public static function getSubscribedEvents()
public static function getSubscribedEvents(): array
{
return [
KernelEvents::RESPONSE => ['onKernelResponse', -1024],

View File

@@ -12,7 +12,7 @@
namespace Symfony\Component\HttpKernel\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\HttpCache\HttpCache;
use Symfony\Component\HttpKernel\HttpCache\SurrogateInterface;
use Symfony\Component\HttpKernel\KernelEvents;
@@ -22,7 +22,7 @@ use Symfony\Component\HttpKernel\KernelEvents;
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.3
* @final
*/
class SurrogateListener implements EventSubscriberInterface
{
@@ -36,9 +36,9 @@ class SurrogateListener implements EventSubscriberInterface
/**
* Filters the Response.
*/
public function onKernelResponse(FilterResponseEvent $event)
public function onKernelResponse(ResponseEvent $event)
{
if (!$event->isMasterRequest()) {
if (!$event->isMainRequest()) {
return;
}
@@ -58,7 +58,7 @@ class SurrogateListener implements EventSubscriberInterface
$surrogate->addSurrogateControl($event->getResponse());
}
public static function getSubscribedEvents()
public static function getSubscribedEvents(): array
{
return [
KernelEvents::RESPONSE => 'onKernelResponse',

View File

@@ -14,12 +14,16 @@ namespace Symfony\Component\HttpKernel\EventListener;
use Psr\Container\ContainerInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
trigger_deprecation('symfony/http-kernel', '5.4', '"%s" is deprecated, use "%s" instead.', TestSessionListener::class, SessionListener::class);
/**
* Sets the session in the request.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final
*
* @deprecated since Symfony 5.4, use SessionListener instead
*/
class TestSessionListener extends AbstractTestSessionListener
{
@@ -33,10 +37,10 @@ class TestSessionListener extends AbstractTestSessionListener
protected function getSession(): ?SessionInterface
{
if (!$this->container->has('session')) {
return null;
if ($this->container->has('session')) {
return $this->container->get('session');
}
return $this->container->get('session');
return null;
}
}

View File

@@ -1,80 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\EventListener;
@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;
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
{
private $translator;
private $requestStack;
/**
* @param LocaleAwareInterface $translator
*/
public function __construct($translator, RequestStack $requestStack)
{
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;
}
public function onKernelRequest(GetResponseEvent $event)
{
$this->setLocale($event->getRequest());
}
public function onKernelFinishRequest(FinishRequestEvent $event)
{
if (null === $parentRequest = $this->requestStack->getParentRequest()) {
return;
}
$this->setLocale($parentRequest);
}
public static function getSubscribedEvents()
{
return [
// must be registered after the Locale listener
KernelEvents::REQUEST => [['onKernelRequest', 10]],
KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', 0]],
];
}
private function setLocale(Request $request)
{
try {
$this->translator->setLocale($request->getLocale());
} catch (\InvalidArgumentException $e) {
$this->translator->setLocale($request->getDefaultLocale());
}
}
}

View File

@@ -12,7 +12,7 @@
namespace Symfony\Component\HttpKernel\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
@@ -20,16 +20,16 @@ use Symfony\Component\HttpKernel\KernelEvents;
*
* @author Magnus Nordlander <magnus@fervo.se>
*
* @final since Symfony 4.3
* @final
*/
class ValidateRequestListener implements EventSubscriberInterface
{
/**
* Performs the validation.
*/
public function onKernelRequest(GetResponseEvent $event)
public function onKernelRequest(RequestEvent $event)
{
if (!$event->isMasterRequest()) {
if (!$event->isMainRequest()) {
return;
}
$request = $event->getRequest();
@@ -44,7 +44,7 @@ class ValidateRequestListener implements EventSubscriberInterface
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents()
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => [

View File

@@ -24,6 +24,12 @@ class AccessDeniedHttpException extends HttpException
*/
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
parent::__construct(403, $message, $previous, $headers, $code);
}
}

View File

@@ -23,6 +23,12 @@ class BadRequestHttpException extends HttpException
*/
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
parent::__construct(400, $message, $previous, $headers, $code);
}
}

View File

@@ -23,6 +23,12 @@ class ConflictHttpException extends HttpException
*/
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
parent::__construct(409, $message, $previous, $headers, $code);
}
}

View File

@@ -23,6 +23,12 @@ class GoneHttpException extends HttpException
*/
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
parent::__construct(410, $message, $previous, $headers, $code);
}
}

View File

@@ -23,6 +23,17 @@ class HttpException extends \RuntimeException implements HttpExceptionInterface
public function __construct(int $statusCode, ?string $message = '', \Throwable $previous = null, array $headers = [], ?int $code = 0)
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
if (null === $code) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $code to "%s()" is deprecated, pass 0 instead.', __METHOD__);
$code = 0;
}
$this->statusCode = $statusCode;
$this->headers = $headers;

View File

@@ -21,14 +21,14 @@ interface HttpExceptionInterface extends \Throwable
/**
* Returns the status code.
*
* @return int An HTTP response status code
* @return int
*/
public function getStatusCode();
/**
* Returns response headers.
*
* @return array Response headers
* @return array
*/
public function getHeaders();
}

View File

@@ -0,0 +1,16 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Exception;
class InvalidMetadataException extends \LogicException
{
}

View File

@@ -23,6 +23,12 @@ class LengthRequiredHttpException extends HttpException
*/
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
parent::__construct(411, $message, $previous, $headers, $code);
}
}

View File

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

View File

@@ -23,6 +23,12 @@ class NotAcceptableHttpException extends HttpException
*/
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
parent::__construct(406, $message, $previous, $headers, $code);
}
}

View File

@@ -23,6 +23,12 @@ class NotFoundHttpException extends HttpException
*/
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
parent::__construct(404, $message, $previous, $headers, $code);
}
}

View File

@@ -23,6 +23,12 @@ class PreconditionFailedHttpException extends HttpException
*/
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
parent::__construct(412, $message, $previous, $headers, $code);
}
}

View File

@@ -25,6 +25,12 @@ class PreconditionRequiredHttpException extends HttpException
*/
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
parent::__construct(428, $message, $previous, $headers, $code);
}
}

View File

@@ -24,6 +24,17 @@ class ServiceUnavailableHttpException extends HttpException
*/
public function __construct($retryAfter = null, ?string $message = '', \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
if (null === $code) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $code to "%s()" is deprecated, pass 0 instead.', __METHOD__);
$code = 0;
}
if ($retryAfter) {
$headers['Retry-After'] = $retryAfter;
}

View File

@@ -26,6 +26,17 @@ class TooManyRequestsHttpException extends HttpException
*/
public function __construct($retryAfter = null, ?string $message = '', \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
if (null === $code) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $code to "%s()" is deprecated, pass 0 instead.', __METHOD__);
$code = 0;
}
if ($retryAfter) {
$headers['Retry-After'] = $retryAfter;
}

View File

@@ -24,6 +24,17 @@ class UnauthorizedHttpException extends HttpException
*/
public function __construct(string $challenge, ?string $message = '', \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
if (null === $code) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $code to "%s()" is deprecated, pass 0 instead.', __METHOD__);
$code = 0;
}
$headers['WWW-Authenticate'] = $challenge;
parent::__construct(401, $message, $previous, $headers, $code);

View File

@@ -0,0 +1,19 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Exception;
/**
* @author Mathias Arlaud <mathias.arlaud@gmail.com>
*/
class UnexpectedSessionUsageException extends \LogicException
{
}

View File

@@ -23,6 +23,12 @@ class UnprocessableEntityHttpException extends HttpException
*/
public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
{
if (null === $message) {
trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__);
$message = '';
}
parent::__construct(422, $message, $previous, $headers, $code);
}
}

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