upgrade to laravel 7 and set branch to v2

This commit is contained in:
2020-12-25 11:22:15 +00:00
parent 516105c492
commit 0ddd298350
4638 changed files with 132501 additions and 190226 deletions

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\Attribute;
/**
* Marker interface for controller argument attributes.
*/
interface ArgumentInterface
{
}

View File

@@ -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

@@ -1,6 +1,60 @@
CHANGELOG
=========
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

@@ -30,7 +30,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

@@ -23,12 +23,12 @@ class Psr6CacheClearer implements CacheClearerInterface
$this->pools = $pools;
}
public function hasPool($name)
public function hasPool(string $name)
{
return isset($this->pools[$name]);
}
public function getPool($name)
public function getPool(string $name)
{
if (!$this->hasPool($name)) {
throw new \InvalidArgumentException(sprintf('Cache pool not found: "%s".', $name));
@@ -37,7 +37,7 @@ class Psr6CacheClearer implements CacheClearerInterface
return $this->pools[$name];
}
public function clearPool($name)
public function clearPool(string $name)
{
if (!isset($this->pools[$name])) {
throw new \InvalidArgumentException(sprintf('Cache pool not found: "%s".', $name));
@@ -49,7 +49,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

@@ -46,9 +46,9 @@ class CacheWarmerAggregate implements CacheWarmerInterface
/**
* 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)
{
if ($collectDeprecations = $this->debug && !\defined('PHPUNIT_COMPOSER_INSTALL')) {
$collectedLogs = [];
@@ -85,6 +85,7 @@ class CacheWarmerAggregate implements CacheWarmerInterface
});
}
$preload = [];
try {
foreach ($this->warmers as $warmer) {
if (!$this->optionalsEnabled && $warmer->isOptional()) {
@@ -94,13 +95,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));
$collectedLogs = array_merge($previousLogs, $collectedLogs);
}
@@ -108,6 +109,8 @@ class CacheWarmerAggregate implements CacheWarmerInterface
file_put_contents($this->deprecationLogsFilepath, serialize(array_values($collectedLogs)));
}
}
return array_values(array_unique(array_merge([], ...$preload)));
}
/**

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 (0 === strpos($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 && 0 === strpos($location, $currentPath)) {
return $locations;
}
if (0 === strpos($location, $deprecatedPath) && (null === $currentPath || false === strpos($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

@@ -43,7 +43,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 +62,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

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
*
* @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
*
* @throws \InvalidArgumentException When the controller cannot be created
*/
protected function createController($controller)
protected function createController(string $controller)
{
if (false === strpos($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.
*
@@ -24,8 +26,9 @@ class ArgumentMetadata
private $hasDefaultValue;
private $defaultValue;
private $isNullable;
private $attribute;
public function __construct(string $name, ?string $type, bool $isVariadic, bool $hasDefaultValue, $defaultValue, bool $isNullable = false)
public function __construct(string $name, ?string $type, bool $isVariadic, bool $hasDefaultValue, $defaultValue, bool $isNullable = false, ?ArgumentInterface $attribute = null)
{
$this->name = $name;
$this->type = $type;
@@ -33,6 +36,7 @@ class ArgumentMetadata
$this->hasDefaultValue = $hasDefaultValue;
$this->defaultValue = $defaultValue;
$this->isNullable = $isNullable || null === $type || ($hasDefaultValue && null === $defaultValue);
$this->attribute = $attribute;
}
/**
@@ -104,4 +108,12 @@ class ArgumentMetadata
return $this->defaultValue;
}
/**
* Returns the attribute (if any) that was set on the argument.
*/
public function getAttribute(): ?ArgumentInterface
{
return $this->attribute;
}
}

View File

@@ -11,6 +11,9 @@
namespace Symfony\Component\HttpKernel\ControllerMetadata;
use Symfony\Component\HttpKernel\Attribute\ArgumentInterface;
use Symfony\Component\HttpKernel\Exception\InvalidMetadataException;
/**
* Builds {@see ArgumentMetadata} objects based on the given Controller.
*
@@ -34,7 +37,28 @@ final class ArgumentMetadataFactory implements ArgumentMetadataFactoryInterface
}
foreach ($reflection->getParameters() as $param) {
$arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $reflection), $param->isVariadic(), $param->isDefaultValueAvailable(), $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, $param->allowsNull());
$attribute = null;
if (\PHP_VERSION_ID >= 80000) {
$reflectionAttributes = $param->getAttributes(ArgumentInterface::class, \ReflectionAttribute::IS_INSTANCEOF);
if (\count($reflectionAttributes) > 1) {
$representative = $controller;
if (\is_array($representative)) {
$representative = sprintf('%s::%s()', \get_class($representative[0]), $representative[1]);
} elseif (\is_object($representative)) {
$representative = \get_class($representative);
}
throw new InvalidMetadataException(sprintf('Controller "%s" has more than one attribute for "$%s" argument.', $representative, $param->getName()));
}
if (isset($reflectionAttributes[0])) {
$attribute = $reflectionAttributes[0]->newInstance();
}
}
$arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $reflection), $param->isVariadic(), $param->isDefaultValueAvailable(), $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, $param->allowsNull(), $attribute);
}
return $arguments;

View File

@@ -19,16 +19,11 @@ use Symfony\Component\HttpFoundation\Response;
*
* @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
}

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,14 +39,10 @@ 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)
{
$this->data = [
'app_name' => $this->name,
'app_version' => $this->version,
'token' => $response->headers->get('X-Debug-Token'),
'symfony_version' => Kernel::VERSION,
'symfony_state' => 'unknown',
@@ -111,26 +92,6 @@ 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.
*
@@ -246,20 +207,6 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
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.
*

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,19 +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) {
@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,10 +24,8 @@ 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.

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
{
@@ -100,12 +100,7 @@ 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 = [];
@@ -187,12 +182,12 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
self::__construct($this->stopwatch, $fileLinkFormat, $charset);
}
public function getDumpsCount()
public function getDumpsCount(): int
{
return $this->dataCount;
}
public function getDumps($format, $maxDepthLimit = -1, $maxItemsPerDepth = -1)
public function getDumps($format, $maxDepthLimit = -1, $maxItemsPerDepth = -1): array
{
$data = fopen('php://memory', 'r+b');
@@ -219,7 +214,7 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
return $dumps;
}
public function getName()
public function getName(): string
{
return 'dump';
}

View File

@@ -12,7 +12,6 @@
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;
@@ -24,7 +23,7 @@ use Symfony\Contracts\Service\ResetInterface;
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.4
* @final
*/
class EventDataCollector extends DataCollector implements LateDataCollectorInterface
{
@@ -40,10 +39,8 @@ 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->data = [
@@ -64,12 +61,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));
}

View File

@@ -20,19 +20,15 @@ use Symfony\Component\HttpFoundation\Response;
*
* @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),

View File

@@ -22,7 +22,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
{
@@ -43,10 +43,8 @@ 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;
}
@@ -124,7 +122,7 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
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 [];
}
@@ -150,7 +148,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

@@ -19,7 +19,7 @@ use Symfony\Component\HttpFoundation\Response;
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.4
* @final
*/
class MemoryDataCollector extends DataCollector implements LateDataCollectorInterface
{
@@ -30,10 +30,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();
}

View File

@@ -15,31 +15,35 @@ 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;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.4
* @final
*/
class RequestDataCollector extends DataCollector implements EventSubscriberInterface, LateDataCollectorInterface
{
protected $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 +90,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' => isset(Response::$statusTexts[$statusCode]) ? Response::$statusTexts[$statusCode] : '',
'status_code' => $statusCode,
@@ -102,6 +105,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 && $this->requestStack->getMasterRequest()->attributes->get('_stateless', false),
'flashes' => $flashes,
'path_info' => $request->getPathInfo(),
'controller' => 'n/a',
@@ -118,9 +123,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 +181,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
{
$this->data = [];
$this->controllers = new \SplObjectStorage();
$this->sessionUsages = [];
}
public function getMethod()
@@ -239,6 +249,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();
@@ -347,18 +367,12 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
return isset($this->data['forward_token']) ? $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()) {
return;
@@ -385,6 +399,37 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
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.
*
@@ -403,7 +448,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 +457,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',

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>
@@ -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();
}

View File

@@ -20,7 +20,7 @@ use Symfony\Component\Stopwatch\StopwatchEvent;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.4
* @final
*/
class TimeDataCollector extends DataCollector implements LateDataCollectorInterface
{
@@ -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();

View File

@@ -20,7 +20,7 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
*
* @author Jérémy Romey <jeremy@free-agent.fr>
*
* @final since Symfony 4.3
* @final
*/
class FileLinkFormatter
{
@@ -46,7 +46,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 +75,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;

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:
@@ -60,7 +60,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

@@ -35,7 +35,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

@@ -53,6 +53,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);
@@ -170,15 +177,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, $p->name) : 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

@@ -43,6 +43,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 +56,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

@@ -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.

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 Whether a response was set
*/
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,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 execute logic after a response was sent.
*
@@ -18,9 +22,20 @@ namespace Symfony\Component\HttpKernel\Event;
* will always return the value of `HttpKernelInterface::MASTER_REQUEST`.
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*
* @final since Symfony 4.4
*/
class TerminateEvent extends PostResponseEvent
final class TerminateEvent extends KernelEvent
{
private $response;
public function __construct(HttpKernelInterface $kernel, Request $request, Response $response)
{
parent::__construct($kernel, $request, HttpKernelInterface::MASTER_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 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): void
{
$this->controllerResult = $controllerResult;
}
}

View File

@@ -15,9 +15,10 @@ use Psr\Container\ContainerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
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;
/**
@@ -33,7 +34,7 @@ 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
{
@@ -41,13 +42,15 @@ abstract class AbstractSessionListener implements EventSubscriberInterface
protected $container;
private $sessionUsageStack = [];
private $debug;
public function __construct(ContainerInterface $container = null)
public function __construct(ContainerInterface $container = null, bool $debug = false)
{
$this->container = $container;
$this->debug = $debug;
}
public function onKernelRequest(GetResponseEvent $event)
public function onKernelRequest(RequestEvent $event)
{
if (!$event->isMasterRequest()) {
return;
@@ -64,7 +67,7 @@ abstract class AbstractSessionListener implements EventSubscriberInterface
$this->sessionUsageStack[] = $session instanceof Session ? $session->getUsageIndex() : 0;
}
public function onKernelResponse(FilterResponseEvent $event)
public function onKernelResponse(ResponseEvent $event)
{
if (!$event->isMasterRequest()) {
return;
@@ -79,16 +82,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.
@@ -117,11 +110,32 @@ abstract class AbstractSessionListener implements EventSubscriberInterface
*/
$session->save();
}
if ($session instanceof Session ? $session->getUsageIndex() === end($this->sessionUsageStack) : !$session->isStarted()) {
return;
}
if ($autoCacheControl) {
$response
->setExpires(new \DateTime())
->setPrivate()
->setMaxAge(0)
->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()) {
@@ -129,7 +143,42 @@ abstract class AbstractSessionListener implements EventSubscriberInterface
}
}
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],

View File

@@ -15,8 +15,8 @@ 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;
/**
@@ -27,7 +27,7 @@ use Symfony\Component\HttpKernel\KernelEvents;
* @author Bulat Shakirzyanov <mallluhuct@gmail.com>
* @author Fabien Potencier <fabien@symfony.com>
*
* @internal since Symfony 4.3
* @internal
*/
abstract class AbstractTestSessionListener implements EventSubscriberInterface
{
@@ -39,7 +39,7 @@ abstract class AbstractTestSessionListener implements EventSubscriberInterface
$this->sessionOptions = $sessionOptions;
}
public function onKernelRequest(GetResponseEvent $event)
public function onKernelRequest(RequestEvent $event)
{
if (!$event->isMasterRequest()) {
return;
@@ -62,7 +62,7 @@ abstract class AbstractTestSessionListener implements EventSubscriberInterface
* Checks if session was initialized and saves if current request is master
* Runs on 'kernel.response' in test environment.
*/
public function onKernelResponse(FilterResponseEvent $event)
public function onKernelResponse(ResponseEvent $event)
{
if (!$event->isMasterRequest()) {
return;
@@ -97,7 +97,7 @@ abstract class AbstractTestSessionListener implements EventSubscriberInterface
}
}
public static function getSubscribedEvents()
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => ['onKernelRequest', 192],

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,10 +15,7 @@ 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;
@@ -29,12 +26,13 @@ use Symfony\Component\HttpKernel\KernelEvents;
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
* @final
*/
class DebugHandlersListener implements EventSubscriberInterface
{
private $exceptionHandler;
private $logger;
private $deprecationLogger;
private $levels;
private $throwAt;
private $scream;
@@ -51,7 +49,7 @@ class DebugHandlersListener implements EventSubscriberInterface
* @param string|FileLinkFormatter|null $fileLinkFormat The format for links to source files
* @param bool $scope Enables/disables scoping mode
*/
public function __construct(callable $exceptionHandler = null, LoggerInterface $logger = null, $levels = \E_ALL, ?int $throwAt = \E_ALL, bool $scream = true, $fileLinkFormat = null, bool $scope = true)
public function __construct(callable $exceptionHandler = null, LoggerInterface $logger = null, $levels = \E_ALL, ?int $throwAt = \E_ALL, bool $scream = true, $fileLinkFormat = null, bool $scope = true, LoggerInterface $deprecationLogger = null)
{
$this->exceptionHandler = $exceptionHandler;
$this->logger = $logger;
@@ -60,12 +58,13 @@ class DebugHandlersListener implements EventSubscriberInterface
$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;
@@ -79,31 +78,30 @@ class DebugHandlersListener implements EventSubscriberInterface
$handler = \is_array($handler) ? $handler[0] : null;
restore_exception_handler();
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) {
@@ -126,27 +124,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,11 @@ 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\HttpExceptionInterface;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
@@ -33,7 +33,7 @@ class ErrorListener implements EventSubscriberInterface
protected $logger;
protected $debug;
public function __construct($controller, LoggerInterface $logger = null, $debug = false)
public function __construct($controller, LoggerInterface $logger = null, bool $debug = false)
{
$this->controller = $controller;
$this->logger = $logger;
@@ -47,7 +47,7 @@ class ErrorListener implements EventSubscriberInterface
$this->logException($event->getThrowable(), sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', $e->getClass(), $e->getMessage(), $e->getFile(), $e->getLine()));
}
public function onKernelException(ExceptionEvent $event, string $eventName = null, EventDispatcherInterface $eventDispatcher = null)
public function onKernelException(ExceptionEvent $event)
{
if (null === $this->controller) {
return;
@@ -79,12 +79,15 @@ class ErrorListener implements EventSubscriberInterface
$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,6 +117,7 @@ class ErrorListener implements EventSubscriberInterface
['logKernelException', 0],
['onKernelException', -128],
],
KernelEvents::RESPONSE => ['removeCspHeader', -128],
];
}

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();
@@ -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

@@ -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,7 +25,7 @@ use Symfony\Component\Routing\RequestContextAwareInterface;
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.3
* @final
*/
class LocaleListener implements EventSubscriberInterface
{
@@ -45,7 +45,7 @@ class LocaleListener implements EventSubscriberInterface
$event->getRequest()->setDefaultLocale($this->defaultLocale);
}
public function onKernelRequest(GetResponseEvent $event)
public function onKernelRequest(RequestEvent $event)
{
$request = $event->getRequest();
@@ -74,7 +74,7 @@ class LocaleListener implements EventSubscriberInterface
}
}
public static function getSubscribedEvents()
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => [

View File

@@ -14,9 +14,9 @@ namespace Symfony\Component\HttpKernel\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
use Symfony\Component\HttpFoundation\RequestStack;
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\Profiler;
@@ -25,7 +25,7 @@ use Symfony\Component\HttpKernel\Profiler\Profiler;
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.3
* @final
*/
class ProfilerListener implements EventSubscriberInterface
{
@@ -56,7 +56,7 @@ class ProfilerListener implements EventSubscriberInterface
/**
* Handles the onKernelException event.
*/
public function onKernelException(GetResponseForExceptionEvent $event)
public function onKernelException(ExceptionEvent $event)
{
if ($this->onlyMasterRequests && !$event->isMasterRequest()) {
return;
@@ -68,7 +68,7 @@ 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) {
@@ -96,7 +96,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) {
@@ -116,7 +116,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,7 +20,7 @@ use Symfony\Component\HttpKernel\KernelEvents;
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.3
* @final
*/
class ResponseListener implements EventSubscriberInterface
{
@@ -34,7 +34,7 @@ class ResponseListener implements EventSubscriberInterface
/**
* Filters the Response.
*/
public function onKernelResponse(FilterResponseEvent $event)
public function onKernelResponse(ResponseEvent $event)
{
if (!$event->isMasterRequest()) {
return;
@@ -49,7 +49,7 @@ class ResponseListener implements EventSubscriberInterface
$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
{
@@ -94,7 +94,7 @@ class RouterListener implements EventSubscriberInterface
$this->setCurrentRequest($this->requestStack->getParentRequest());
}
public function onKernelRequest(GetResponseEvent $event)
public function onKernelRequest(RequestEvent $event)
{
$request = $event->getRequest();
@@ -141,7 +141,7 @@ class RouterListener implements EventSubscriberInterface
}
}
public function onKernelException(GetResponseForExceptionEvent $event)
public function onKernelException(ExceptionEvent $event)
{
if (!$this->debug || !($e = $event->getThrowable()) instanceof NotFoundHttpException) {
return;
@@ -152,7 +152,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

@@ -28,9 +28,9 @@ use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
*/
class SessionListener extends AbstractSessionListener
{
public function __construct(ContainerInterface $container)
public function __construct(ContainerInterface $container, bool $debug = false)
{
$this->container = $container;
parent::__construct($container, $debug);
}
protected function getSession(): ?SessionInterface

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,14 +22,14 @@ 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()) {
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,7 +36,7 @@ class SurrogateListener implements EventSubscriberInterface
/**
* Filters the Response.
*/
public function onKernelResponse(FilterResponseEvent $event)
public function onKernelResponse(ResponseEvent $event)
{
if (!$event->isMasterRequest()) {
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

@@ -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,14 +20,14 @@ 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()) {
return;
@@ -44,7 +44,7 @@ class ValidateRequestListener implements EventSubscriberInterface
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents()
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => [

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

@@ -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

@@ -15,6 +15,7 @@ use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpKernel\Controller\ControllerReference;
use Symfony\Component\HttpKernel\Exception\HttpException;
/**
* Renders a URI that represents a resource fragment.
@@ -60,15 +61,14 @@ class FragmentHandler
*
* * ignore_errors: true to return an empty string in case of an error
*
* @param string|ControllerReference $uri A URI as a string or a ControllerReference instance
* @param string $renderer The renderer name
* @param string|ControllerReference $uri A URI as a string or a ControllerReference instance
*
* @return string|null The Response content or null when the Response is streamed
*
* @throws \InvalidArgumentException when the renderer does not exist
* @throws \LogicException when no master request is being handled
*/
public function render($uri, $renderer = 'inline', array $options = [])
public function render($uri, string $renderer = 'inline', array $options = [])
{
if (!isset($options['ignore_errors'])) {
$options['ignore_errors'] = !$this->debug;
@@ -98,7 +98,8 @@ class FragmentHandler
protected function deliver(Response $response)
{
if (!$response->isSuccessful()) {
throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %d).', $this->requestStack->getCurrentRequest()->getUri(), $response->getStatusCode()));
$responseStatusCode = $response->getStatusCode();
throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %d).', $this->requestStack->getCurrentRequest()->getUri(), $responseStatusCode), 0, new HttpException($responseStatusCode));
}
if (!$response instanceof StreamedResponse) {

View File

@@ -15,11 +15,7 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Controller\ControllerReference;
use Symfony\Component\HttpKernel\UriSigner;
use Symfony\Component\Templating\EngineInterface;
use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Loader\ExistsLoaderInterface;
use Twig\Loader\SourceContextLoaderInterface;
/**
* Implements the Hinclude rendering strategy.
@@ -30,43 +26,20 @@ class HIncludeFragmentRenderer extends RoutableFragmentRenderer
{
private $globalDefaultTemplate;
private $signer;
private $templating;
private $twig;
private $charset;
/**
* @param EngineInterface|Environment $templating An EngineInterface or a Twig instance
* @param string $globalDefaultTemplate The global default content (it can be a template name or the content)
* @param string $globalDefaultTemplate The global default content (it can be a template name or the content)
*/
public function __construct($templating = null, UriSigner $signer = null, string $globalDefaultTemplate = null, string $charset = 'utf-8')
public function __construct(Environment $twig = null, UriSigner $signer = null, string $globalDefaultTemplate = null, string $charset = 'utf-8')
{
$this->setTemplating($templating);
$this->twig = $twig;
$this->globalDefaultTemplate = $globalDefaultTemplate;
$this->signer = $signer;
$this->charset = $charset;
}
/**
* Sets the templating engine to use to render the default content.
*
* @param EngineInterface|Environment|null $templating An EngineInterface or an Environment instance
*
* @throws \InvalidArgumentException
*
* @internal
*/
public function setTemplating($templating)
{
if (null !== $templating && !$templating instanceof EngineInterface && !$templating instanceof Environment) {
throw new \InvalidArgumentException('The hinclude rendering strategy needs an instance of Twig\Environment or Symfony\Component\Templating\EngineInterface.');
}
if ($templating instanceof EngineInterface) {
@trigger_error(sprintf('Using a "%s" instance for "%s" is deprecated since version 4.3; use a \Twig\Environment instance instead.', EngineInterface::class, __CLASS__), \E_USER_DEPRECATED);
}
$this->templating = $templating;
}
/**
* Checks if a templating engine has been set.
*
@@ -74,7 +47,7 @@ class HIncludeFragmentRenderer extends RoutableFragmentRenderer
*/
public function hasTemplating()
{
return null !== $this->templating;
return null !== $this->twig;
}
/**
@@ -101,8 +74,8 @@ class HIncludeFragmentRenderer extends RoutableFragmentRenderer
$uri = str_replace('&', '&amp;', $uri);
$template = isset($options['default']) ? $options['default'] : $this->globalDefaultTemplate;
if (null !== $this->templating && $template && $this->templateExists($template)) {
$content = $this->templating->render($template);
if (null !== $this->twig && $template && $this->twig->getLoader()->exists($template)) {
$content = $this->twig->render($template);
} else {
$content = $template;
}
@@ -126,36 +99,6 @@ class HIncludeFragmentRenderer extends RoutableFragmentRenderer
return new Response(sprintf('<hx:include src="%s"%s>%s</hx:include>', $uri, $renderedAttributes, $content));
}
private function templateExists(string $template): bool
{
if ($this->templating instanceof EngineInterface) {
try {
return $this->templating->exists($template);
} catch (\Exception $e) {
return false;
}
}
$loader = $this->templating->getLoader();
if (1 === Environment::MAJOR_VERSION && !$loader instanceof ExistsLoaderInterface) {
try {
if ($loader instanceof SourceContextLoaderInterface) {
$loader->getSourceContext($template);
} else {
$loader->getSource($template);
}
return true;
} catch (LoaderError $e) {
}
return false;
}
return $loader->exists($template);
}
/**
* {@inheritdoc}
*/

View File

@@ -11,7 +11,6 @@
namespace Symfony\Component\HttpKernel\Fragment;
use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Controller\ControllerReference;
@@ -34,7 +33,7 @@ class InlineFragmentRenderer extends RoutableFragmentRenderer
public function __construct(HttpKernelInterface $kernel, EventDispatcherInterface $dispatcher = null)
{
$this->kernel = $kernel;
$this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher);
$this->dispatcher = $dispatcher;
}
/**

View File

@@ -27,11 +27,9 @@ abstract class RoutableFragmentRenderer implements FragmentRendererInterface
/**
* Sets the fragment path that triggers the fragment listener.
*
* @param string $path The path
*
* @see FragmentListener
*/
public function setFragmentPath($path)
public function setFragmentPath(string $path)
{
$this->fragmentPath = $path;
}
@@ -44,7 +42,7 @@ abstract class RoutableFragmentRenderer implements FragmentRendererInterface
*
* @return string A fragment URI
*/
protected function generateFragmentUri(ControllerReference $reference, Request $request, $absolute = false, $strict = true)
protected function generateFragmentUri(ControllerReference $reference, Request $request, bool $absolute = false, bool $strict = true)
{
if ($strict) {
$this->checkNonScalar($reference->attributes);

View File

@@ -88,7 +88,7 @@ abstract class AbstractSurrogate implements SurrogateInterface
/**
* {@inheritdoc}
*/
public function handle(HttpCache $cache, $uri, $alt, $ignoreErrors)
public function handle(HttpCache $cache, string $uri, string $alt, bool $ignoreErrors)
{
$subRequest = Request::create($uri, Request::METHOD_GET, [], $cache->getRequest()->cookies->all(), [], $cache->getRequest()->server->all());

View File

@@ -45,7 +45,7 @@ class Esi extends AbstractSurrogate
/**
* {@inheritdoc}
*/
public function renderIncludeTag($uri, $alt = null, $ignoreErrors = true, $comment = '')
public function renderIncludeTag(string $uri, string $alt = null, bool $ignoreErrors = true, string $comment = '')
{
$html = sprintf('<esi:include src="%s"%s%s />',
$uri,

View File

@@ -190,7 +190,7 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
/**
* {@inheritdoc}
*/
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
public function handle(Request $request, int $type = HttpKernelInterface::MASTER_REQUEST, bool $catch = true)
{
// FIXME: catch exceptions and implement a 500 error page here? -> in Varnish, there is a built-in error page mechanism
if (HttpKernelInterface::MASTER_REQUEST === $type) {
@@ -260,7 +260,7 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
*
* @return Response A Response instance
*/
protected function pass(Request $request, $catch = false)
protected function pass(Request $request, bool $catch = false)
{
$this->record($request, 'pass');
@@ -278,7 +278,7 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
*
* @see RFC2616 13.10
*/
protected function invalidate(Request $request, $catch = false)
protected function invalidate(Request $request, bool $catch = false)
{
$response = $this->pass($request, $catch);
@@ -324,7 +324,7 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
*
* @throws \Exception
*/
protected function lookup(Request $request, $catch = false)
protected function lookup(Request $request, bool $catch = false)
{
try {
$entry = $this->store->lookup($request);
@@ -371,7 +371,7 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
*
* @return Response A Response instance
*/
protected function validate(Request $request, Response $entry, $catch = false)
protected function validate(Request $request, Response $entry, bool $catch = false)
{
$subRequest = clone $request;
@@ -434,7 +434,7 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
*
* @return Response A Response instance
*/
protected function fetch(Request $request, $catch = false)
protected function fetch(Request $request, bool $catch = false)
{
$subRequest = clone $request;
@@ -467,7 +467,7 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
*
* @return Response A Response instance
*/
protected function forward(Request $request, $catch = false, Response $entry = null)
protected function forward(Request $request, bool $catch = false, Response $entry = null)
{
if ($this->surrogate) {
$this->surrogate->addSurrogateCapability($request);

View File

@@ -42,7 +42,7 @@ class Ssi extends AbstractSurrogate
/**
* {@inheritdoc}
*/
public function renderIncludeTag($uri, $alt = null, $ignoreErrors = true, $comment = '')
public function renderIncludeTag(string $uri, string $alt = null, bool $ignoreErrors = true, string $comment = '')
{
return sprintf('<!--#include virtual="%s" -->', $uri);
}

View File

@@ -34,7 +34,7 @@ class Store implements StoreInterface
public function __construct(string $root)
{
$this->root = $root;
if (!file_exists($this->root) && !@mkdir($this->root, 0777, true) && !is_dir($this->root)) {
if (!is_dir($this->root) && !@mkdir($this->root, 0777, true) && !is_dir($this->root)) {
throw new \RuntimeException(sprintf('Unable to create the store directory (%s).', $this->root));
}
$this->keyCache = new \SplObjectStorage();
@@ -66,7 +66,7 @@ class Store implements StoreInterface
if (!isset($this->locks[$key])) {
$path = $this->getPath($key);
if (!file_exists(\dirname($path)) && false === @mkdir(\dirname($path), 0777, true) && !is_dir(\dirname($path))) {
if (!is_dir(\dirname($path)) && false === @mkdir(\dirname($path), 0777, true) && !is_dir(\dirname($path))) {
return $path;
}
$h = fopen($path, 'cb');
@@ -110,7 +110,7 @@ class Store implements StoreInterface
return true; // shortcut if lock held by this process
}
if (!file_exists($path = $this->getPath($key))) {
if (!is_file($path = $this->getPath($key))) {
return false;
}
@@ -207,7 +207,7 @@ class Store implements StoreInterface
$entry[1]['vary'] = [''];
}
if ($entry[1]['vary'][0] != $vary || !$this->requestsMatch($vary, $entry[0], $storedEnv)) {
if ($entry[1]['vary'][0] != $vary || !$this->requestsMatch($vary ?? '', $entry[0], $storedEnv)) {
$entries[] = $entry;
}
}
@@ -265,9 +265,9 @@ class Store implements StoreInterface
* Determines whether two Request HTTP header sets are non-varying based on
* the vary response header value provided.
*
* @param string $vary A Response vary header
* @param array $env1 A Request HTTP header array
* @param array $env2 A Request HTTP header array
* @param string|null $vary A Response vary header
* @param array $env1 A Request HTTP header array
* @param array $env2 A Request HTTP header array
*/
private function requestsMatch(?string $vary, array $env1, array $env2): bool
{
@@ -306,11 +306,9 @@ class Store implements StoreInterface
*
* This method purges both the HTTP and the HTTPS version of the cache entry.
*
* @param string $url A URL
*
* @return bool true if the URL exists with either HTTP or HTTPS scheme and has been purged, false otherwise
*/
public function purge($url)
public function purge(string $url)
{
$http = preg_replace('#^https:#', 'http:', $url);
$https = preg_replace('#^http:#', 'https:', $url);
@@ -333,7 +331,7 @@ class Store implements StoreInterface
unset($this->locks[$key]);
}
if (file_exists($path = $this->getPath($key))) {
if (is_file($path = $this->getPath($key))) {
unlink($path);
return true;
@@ -349,7 +347,7 @@ class Store implements StoreInterface
{
$path = $this->getPath($key);
return file_exists($path) && false !== ($contents = file_get_contents($path)) ? $contents : null;
return is_file($path) && false !== ($contents = file_get_contents($path)) ? $contents : null;
}
/**
@@ -374,7 +372,7 @@ class Store implements StoreInterface
return false;
}
} else {
if (!file_exists(\dirname($path)) && false === @mkdir(\dirname($path), 0777, true) && !is_dir(\dirname($path))) {
if (!is_dir(\dirname($path)) && false === @mkdir(\dirname($path), 0777, true) && !is_dir(\dirname($path))) {
return false;
}
@@ -405,7 +403,7 @@ class Store implements StoreInterface
return true;
}
public function getPath($key)
public function getPath(string $key)
{
return $this->root.\DIRECTORY_SEPARATOR.substr($key, 0, 2).\DIRECTORY_SEPARATOR.substr($key, 2, 2).\DIRECTORY_SEPARATOR.substr($key, 4, 2).\DIRECTORY_SEPARATOR.substr($key, 6);
}

View File

@@ -70,11 +70,9 @@ interface StoreInterface
/**
* Purges data for the given URL.
*
* @param string $url A URL
*
* @return bool true if the URL exists and has been purged, false otherwise
*/
public function purge($url);
public function purge(string $url);
/**
* Cleanups storage.

View File

@@ -23,7 +23,7 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
*/
class SubRequestHandler
{
public static function handle(HttpKernelInterface $kernel, Request $request, $type, $catch): Response
public static function handle(HttpKernelInterface $kernel, Request $request, int $type, bool $catch): Response
{
// save global state related to trusted headers and proxies
$trustedProxies = Request::getTrustedProxies();

View File

@@ -59,14 +59,12 @@ interface SurrogateInterface
/**
* Renders a Surrogate tag.
*
* @param string $uri A URI
* @param string $alt An alternate URI
* @param bool $ignoreErrors Whether to ignore errors or not
* @param string $comment A comment to add as an esi:include tag
* @param string $alt An alternate URI
* @param string $comment A comment to add as an esi:include tag
*
* @return string
*/
public function renderIncludeTag($uri, $alt = null, $ignoreErrors = true, $comment = '');
public function renderIncludeTag(string $uri, string $alt = null, bool $ignoreErrors = true, string $comment = '');
/**
* Replaces a Response Surrogate tags with the included resource content.
@@ -78,14 +76,12 @@ interface SurrogateInterface
/**
* Handles a Surrogate from the cache.
*
* @param string $uri The main URI
* @param string $alt An alternative URI
* @param bool $ignoreErrors Whether to ignore errors or not
* @param string $alt An alternative URI
*
* @return string
*
* @throws \RuntimeException
* @throws \Exception
*/
public function handle(HttpCache $cache, $uri, $alt, $ignoreErrors);
public function handle(HttpCache $cache, string $uri, string $alt, bool $ignoreErrors);
}

View File

@@ -42,7 +42,7 @@ final class HttpClientKernel implements HttpKernelInterface
$this->client = $client ?? HttpClient::create();
}
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true): Response
public function handle(Request $request, int $type = HttpKernelInterface::MASTER_REQUEST, bool $catch = true): Response
{
$headers = $this->getHeaders($request);
$body = '';

View File

@@ -11,7 +11,6 @@
namespace Symfony\Component\HttpKernel;
use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy;
use Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
@@ -59,7 +58,7 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface
public function __construct(EventDispatcherInterface $dispatcher, ControllerResolverInterface $resolver, RequestStack $requestStack = null, ArgumentResolverInterface $argumentResolver = null)
{
$this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher);
$this->dispatcher = $dispatcher;
$this->resolver = $resolver;
$this->requestStack = $requestStack ?: new RequestStack();
$this->argumentResolver = $argumentResolver;
@@ -72,7 +71,7 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface
/**
* {@inheritdoc}
*/
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
public function handle(Request $request, int $type = HttpKernelInterface::MASTER_REQUEST, bool $catch = true)
{
$request->headers->set('X-Php-Ob-Level', (string) ob_get_level());

View File

@@ -11,17 +11,192 @@
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.
* Simulates a browser and makes requests to an HttpKernel instance.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @method Request getRequest() A Request instance
* @method Response getResponse() A Response instance
*/
class HttpKernelBrowser extends Client
class HttpKernelBrowser 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.
*/
public function catchExceptions(bool $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 (0 === strpos($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(), $server = $request->getServer(), $request->getContent());
if (!isset($server['HTTP_ACCEPT'])) {
$httpRequest->headers->remove('Accept');
}
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

@@ -38,5 +38,5 @@ interface HttpKernelInterface
*
* @throws \Exception When an Exception occurs during processing
*/
public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true);
public function handle(Request $request, int $type = self::MASTER_REQUEST, bool $catch = true);
}

View File

@@ -22,6 +22,8 @@ use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
use Symfony\Component\DependencyInjection\Dumper\Preloader;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
use Symfony\Component\DependencyInjection\Loader\DirectoryLoader;
use Symfony\Component\DependencyInjection\Loader\GlobFileLoader;
@@ -34,10 +36,14 @@ use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
use Symfony\Component\HttpKernel\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\AddAnnotatedClassesToCachePass;
use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass;
// Help opcache.preload discover always-needed symbols
class_exists(ConfigCache::class);
/**
* The Kernel is the heart of the Symfony system.
*
@@ -56,17 +62,9 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
protected $bundles = [];
protected $container;
/**
* @deprecated since Symfony 4.2
*/
protected $rootDir;
protected $environment;
protected $debug;
protected $booted = false;
/**
* @deprecated since Symfony 4.2
*/
protected $name;
protected $startTime;
private $projectDir;
@@ -76,22 +74,20 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
private static $freshCache = [];
public const VERSION = '4.4.18';
public const VERSION_ID = 40418;
public const MAJOR_VERSION = 4;
public const MINOR_VERSION = 4;
public const RELEASE_VERSION = 18;
public const VERSION = '5.2.1';
public const VERSION_ID = 50201;
public const MAJOR_VERSION = 5;
public const MINOR_VERSION = 2;
public const RELEASE_VERSION = 1;
public const EXTRA_VERSION = '';
public const END_OF_MAINTENANCE = '11/2022';
public const END_OF_LIFE = '11/2023';
public const END_OF_MAINTENANCE = '07/2021';
public const END_OF_LIFE = '07/2021';
public function __construct(string $environment, bool $debug)
{
$this->environment = $environment;
$this->debug = $debug;
$this->rootDir = $this->getRootDir(false);
$this->name = $this->getName(false);
}
public function __clone()
@@ -120,20 +116,10 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
return;
}
if ($this->debug) {
$this->startTime = microtime(true);
}
if ($this->debug && !isset($_ENV['SHELL_VERBOSITY']) && !isset($_SERVER['SHELL_VERBOSITY'])) {
putenv('SHELL_VERBOSITY=3');
$_ENV['SHELL_VERBOSITY'] = 3;
$_SERVER['SHELL_VERBOSITY'] = 3;
}
// init bundles
$this->initializeBundles();
// init container
$this->initializeContainer();
if (null === $this->container) {
$this->preBoot();
}
foreach ($this->getBundles() as $bundle) {
$bundle->setContainer($this->container);
@@ -146,7 +132,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
/**
* {@inheritdoc}
*/
public function reboot($warmupDir)
public function reboot(?string $warmupDir)
{
$this->shutdown();
$this->warmupDir = $warmupDir;
@@ -191,8 +177,16 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
/**
* {@inheritdoc}
*/
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
public function handle(Request $request, int $type = HttpKernelInterface::MASTER_REQUEST, bool $catch = true)
{
if (!$this->booted) {
$container = $this->container ?? $this->preBoot();
if ($container->has('http_cache')) {
return $container->get('http_cache')->handle($request, $type, $catch);
}
}
$this->boot();
++$this->requestStackSize;
$this->resetServices = true;
@@ -225,7 +219,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
/**
* {@inheritdoc}
*/
public function getBundle($name)
public function getBundle(string $name)
{
if (!isset($this->bundles[$name])) {
throw new \InvalidArgumentException(sprintf('Bundle "%s" does not exist or it is not enabled. Maybe you forgot to add it in the "registerBundles()" method of your "%s.php" file?', $name, get_debug_type($this)));
@@ -237,20 +231,8 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
/**
* {@inheritdoc}
*/
public function locateResource($name/*, $dir = null, $first = true, $triggerDeprecation = true*/)
public function locateResource(string $name)
{
if (2 <= \func_num_args()) {
$dir = func_get_arg(1);
$first = 3 <= \func_num_args() ? func_get_arg(2) : true;
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 {
$dir = null;
$first = true;
}
if ('@' !== $name[0]) {
throw new \InvalidArgumentException(sprintf('A resource name must start with @ ("%s" given).', $name));
}
@@ -265,53 +247,14 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
[$bundleName, $path] = explode('/', $bundleName, 2);
}
$isResource = 0 === strpos($path, 'Resources') && null !== $dir;
$overridePath = substr($path, 9);
$bundle = $this->getBundle($bundleName);
$files = [];
if ($isResource && file_exists($file = $dir.'/'.$bundle->getName().$overridePath)) {
$files[] = $file;
// see https://symfony.com/doc/current/bundles/override.html on how to overwrite parts of a bundle
@trigger_error(sprintf('Overwriting the resource "%s" with "%s" is deprecated since Symfony 4.4 and will be removed in 5.0.', $name, $file), \E_USER_DEPRECATED);
}
if (file_exists($file = $bundle->getPath().'/'.$path)) {
if ($first && !$isResource) {
return $file;
}
$files[] = $file;
}
if (\count($files) > 0) {
return $first && $isResource ? $files[0] : $files;
return $file;
}
throw new \InvalidArgumentException(sprintf('Unable to find file "%s".', $name));
}
/**
* {@inheritdoc}
*
* @deprecated since Symfony 4.2
*/
public function getName(/* $triggerDeprecation = true */)
{
if (0 === \func_num_args() || func_get_arg(0)) {
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED);
}
if (null === $this->name) {
$this->name = preg_replace('/[^a-zA-Z0-9_]+/', '', basename($this->rootDir));
if (ctype_digit($this->name[0])) {
$this->name = '_'.$this->name;
}
}
return $this->name;
}
/**
* {@inheritdoc}
*/
@@ -328,25 +271,6 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
return $this->debug;
}
/**
* {@inheritdoc}
*
* @deprecated since Symfony 4.2, use getProjectDir() instead
*/
public function getRootDir(/* $triggerDeprecation = true */)
{
if (0 === \func_num_args() || func_get_arg(0)) {
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use getProjectDir() instead.', __METHOD__), \E_USER_DEPRECATED);
}
if (null === $this->rootDir) {
$r = new \ReflectionObject($this);
$this->rootDir = \dirname($r->getFileName());
}
return $this->rootDir;
}
/**
* Gets the application root dir (path of the project's composer file).
*
@@ -357,12 +281,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
if (null === $this->projectDir) {
$r = new \ReflectionObject($this);
if (!file_exists($dir = $r->getFileName())) {
if (!is_file($dir = $r->getFileName())) {
throw new \LogicException(sprintf('Cannot auto-detect project dir for kernel of class "%s".', $r->name));
}
$dir = $rootDir = \dirname($dir);
while (!file_exists($dir.'/composer.json')) {
while (!is_file($dir.'/composer.json')) {
if ($dir === \dirname($dir)) {
return $this->projectDir = $rootDir;
}
@@ -380,7 +304,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
public function getContainer()
{
if (!$this->container) {
@trigger_error('Getting the container from a non-booted kernel is deprecated since Symfony 4.4.', \E_USER_DEPRECATED);
throw new \LogicException('Cannot retrieve the container from a non-booted kernel.');
}
return $this->container;
@@ -391,7 +315,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
*/
public function setAnnotatedClassCache(array $annotatedClasses)
{
file_put_contents(($this->warmupDir ?: $this->getCacheDir()).'/annotations.map', sprintf('<?php return %s;', var_export($annotatedClasses, true)));
file_put_contents(($this->warmupDir ?: $this->getBuildDir()).'/annotations.map', sprintf('<?php return %s;', var_export($annotatedClasses, true)));
}
/**
@@ -410,6 +334,15 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
return $this->getProjectDir().'/var/cache/'.$this->environment;
}
/**
* {@inheritdoc}
*/
public function getBuildDir(): string
{
// Returns $this->getCacheDir() for backward compatibility
return $this->getCacheDir();
}
/**
* {@inheritdoc}
*/
@@ -472,7 +405,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
{
$class = static::class;
$class = false !== strpos($class, "@anonymous\0") ? get_parent_class($class).str_replace('.', '_', ContainerBuilder::hash($class)) : $class;
$class = $this->name.str_replace('\\', '_', $class).ucfirst($this->environment).($this->debug ? 'Debug' : '').'Container';
$class = str_replace('\\', '_', $class).ucfirst($this->environment).($this->debug ? 'Debug' : '').'Container';
if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $class)) {
throw new \InvalidArgumentException(sprintf('The environment "%s" contains invalid characters, it can only contain characters allowed in PHP class names.', $this->environment));
@@ -496,21 +429,21 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
/**
* Initializes the service container.
*
* The cached version of the service container is used when fresh, otherwise the
* The built version of the service container is used when fresh, otherwise the
* container is built.
*/
protected function initializeContainer()
{
$class = $this->getContainerClass();
$cacheDir = $this->warmupDir ?: $this->getCacheDir();
$cache = new ConfigCache($cacheDir.'/'.$class.'.php', $this->debug);
$buildDir = $this->warmupDir ?: $this->getBuildDir();
$cache = new ConfigCache($buildDir.'/'.$class.'.php', $this->debug);
$cachePath = $cache->getPath();
// Silence E_WARNING to ignore "include" failures - don't use "@" to prevent silencing fatal errors
$errorLevel = error_reporting(\E_ALL ^ \E_WARNING);
try {
if (file_exists($cachePath) && \is_object($this->container = include $cachePath)
if (is_file($cachePath) && \is_object($this->container = include $cachePath)
&& (!$this->debug || (self::$freshCache[$cachePath] ?? $cache->isFresh()))
) {
self::$freshCache[$cachePath] = true;
@@ -525,7 +458,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
$oldContainer = \is_object($this->container) ? new \ReflectionClass($this->container) : $this->container = null;
try {
is_dir($cacheDir) ?: mkdir($cacheDir, 0777, true);
is_dir($buildDir) ?: mkdir($buildDir, 0777, true);
if ($lock = fopen($cachePath.'.lock', 'w')) {
flock($lock, \LOCK_EX | \LOCK_NB, $wouldBlock);
@@ -569,6 +502,18 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
break;
}
}
for ($i = 0; isset($backtrace[$i]); ++$i) {
if (!isset($backtrace[$i]['file'], $backtrace[$i]['line'], $backtrace[$i]['function'])) {
continue;
}
if (!isset($backtrace[$i]['class']) && 'trigger_deprecation' === $backtrace[$i]['function']) {
$file = $backtrace[$i]['file'];
$line = $backtrace[$i]['line'];
$backtrace = \array_slice($backtrace, 1 + $i);
break;
}
}
// Remove frames added by DebugClassLoader.
for ($i = \count($backtrace) - 2; 0 < $i; --$i) {
if (\in_array($backtrace[$i]['class'] ?? null, [DebugClassLoader::class, LegacyDebugClassLoader::class], true)) {
@@ -598,8 +543,8 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
if ($collectDeprecations) {
restore_error_handler();
file_put_contents($cacheDir.'/'.$class.'Deprecations.log', serialize(array_values($collectedLogs)));
file_put_contents($cacheDir.'/'.$class.'Compiler.log', null !== $container ? implode("\n", $container->getCompiler()->getLog()) : '');
file_put_contents($buildDir.'/'.$class.'Deprecations.log', serialize(array_values($collectedLogs)));
file_put_contents($buildDir.'/'.$class.'Compiler.log', null !== $container ? implode("\n", $container->getCompiler()->getLog()) : '');
}
}
@@ -629,8 +574,14 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
touch($oldContainerDir.'.legacy');
}
$preload = $this instanceof WarmableInterface ? (array) $this->warmUp($this->container->getParameter('kernel.cache_dir')) : [];
if ($this->container->has('cache_warmer')) {
$this->container->get('cache_warmer')->warmUp($this->container->getParameter('kernel.cache_dir'));
$preload = array_merge($preload, (array) $this->container->get('cache_warmer')->warmUp($this->container->getParameter('kernel.cache_dir')));
}
if ($preload && method_exists(Preloader::class, 'append') && file_exists($preloadFile = $buildDir.'/'.$class.'.preload.php')) {
Preloader::append($preloadFile, $preload);
}
}
@@ -653,18 +604,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
}
return [
/*
* @deprecated since Symfony 4.2, use kernel.project_dir instead
*/
'kernel.root_dir' => realpath($this->rootDir) ?: $this->rootDir,
'kernel.project_dir' => realpath($this->getProjectDir()) ?: $this->getProjectDir(),
'kernel.environment' => $this->environment,
'kernel.runtime_environment' => '%env(default:kernel.environment:APP_RUNTIME_ENV)%',
'kernel.debug' => $this->debug,
/*
* @deprecated since Symfony 4.2
*/
'kernel.name' => $this->name,
'kernel.cache_dir' => realpath($cacheDir = $this->warmupDir ?: $this->getCacheDir()) ?: $cacheDir,
'kernel.build_dir' => realpath($buildDir = $this->warmupDir ?: $this->getBuildDir()) ?: $buildDir,
'kernel.cache_dir' => realpath($cacheDir = ($this->getCacheDir() === $this->getBuildDir() ? ($this->warmupDir ?: $this->getCacheDir()) : $this->getCacheDir())) ?: $cacheDir,
'kernel.logs_dir' => realpath($this->getLogDir()) ?: $this->getLogDir(),
'kernel.bundles' => $bundles,
'kernel.bundles_metadata' => $bundlesMetadata,
@@ -682,7 +627,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
*/
protected function buildContainer()
{
foreach (['cache' => $this->warmupDir ?: $this->getCacheDir(), 'logs' => $this->getLogDir()] as $name => $dir) {
foreach (['cache' => $this->getCacheDir(), 'build' => $this->warmupDir ?: $this->getBuildDir(), 'logs' => $this->getLogDir()] as $name => $dir) {
if (!is_dir($dir)) {
if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) {
throw new \RuntimeException(sprintf('Unable to create the "%s" directory (%s).', $name, $dir));
@@ -745,6 +690,9 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
$container = new ContainerBuilder();
$container->getParameterBag()->add($this->getKernelParameters());
if ($this instanceof ExtensionInterface) {
$container->registerExtension($this);
}
if ($this instanceof CompilerPassInterface) {
$container->addCompilerPass($this, PassConfig::TYPE_BEFORE_OPTIMIZATION, -10000);
}
@@ -761,7 +709,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
* @param string $class The name of the class to generate
* @param string $baseClass The name of the container's base class
*/
protected function dumpContainer(ConfigCache $cache, ContainerBuilder $container, $class, $baseClass)
protected function dumpContainer(ConfigCache $cache, ContainerBuilder $container, string $class, string $baseClass)
{
// cache the container
$dumper = new PhpDumper($container);
@@ -789,7 +737,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
@chmod($dir.$file, 0666 & ~umask());
}
$legacyFile = \dirname($dir.key($content)).'.legacy';
if (file_exists($legacyFile)) {
if (is_file($legacyFile)) {
@unlink($legacyFile);
}
@@ -817,17 +765,42 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
return new DelegatingLoader($resolver);
}
private function preBoot(): ContainerInterface
{
if ($this->debug) {
$this->startTime = microtime(true);
}
if ($this->debug && !isset($_ENV['SHELL_VERBOSITY']) && !isset($_SERVER['SHELL_VERBOSITY'])) {
putenv('SHELL_VERBOSITY=3');
$_ENV['SHELL_VERBOSITY'] = 3;
$_SERVER['SHELL_VERBOSITY'] = 3;
}
$this->initializeBundles();
$this->initializeContainer();
$container = $this->container;
if ($container->hasParameter('kernel.trusted_hosts') && $trustedHosts = $container->getParameter('kernel.trusted_hosts')) {
Request::setTrustedHosts($trustedHosts);
}
if ($container->hasParameter('kernel.trusted_proxies') && $container->hasParameter('kernel.trusted_headers') && $trustedProxies = $container->getParameter('kernel.trusted_proxies')) {
Request::setTrustedProxies(\is_array($trustedProxies) ? $trustedProxies : array_map('trim', explode(',', $trustedProxies)), $container->getParameter('kernel.trusted_headers'));
}
return $container;
}
/**
* Removes comments from a PHP source string.
*
* We don't use the PHP php_strip_whitespace() function
* as we want the content to be readable and well-formatted.
*
* @param string $source A PHP string
*
* @return string The PHP string with the comments removed
*/
public static function stripComments($source)
public static function stripComments(string $source)
{
if (!\function_exists('token_get_all')) {
return $source;
@@ -882,51 +855,16 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
return $output;
}
/**
* @deprecated since Symfony 4.3
*/
public function serialize()
{
@trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.3.', __METHOD__), \E_USER_DEPRECATED);
return serialize([$this->environment, $this->debug]);
}
/**
* @deprecated since Symfony 4.3
*/
public function unserialize($data)
{
@trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.3.', __METHOD__), \E_USER_DEPRECATED);
[$environment, $debug] = unserialize($data, ['allowed_classes' => false]);
$this->__construct($environment, $debug);
}
/**
* @return array
*/
public function __sleep()
{
if (__CLASS__ !== $c = (new \ReflectionMethod($this, 'serialize'))->getDeclaringClass()->name) {
@trigger_error(sprintf('Implementing the "%s::serialize()" method is deprecated since Symfony 4.3.', $c), \E_USER_DEPRECATED);
$this->serialized = $this->serialize();
return ['serialized'];
}
return ['environment', 'debug'];
}
public function __wakeup()
{
if (__CLASS__ !== $c = (new \ReflectionMethod($this, 'serialize'))->getDeclaringClass()->name) {
@trigger_error(sprintf('Implementing the "%s::serialize()" method is deprecated since Symfony 4.3.', $c), \E_USER_DEPRECATED);
$this->unserialize($this->serialized);
unset($this->serialized);
return;
}
$this->__construct($this->environment, $this->debug);
}
}

View File

@@ -11,6 +11,15 @@
namespace Symfony\Component\HttpKernel;
use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\Event\TerminateEvent;
use Symfony\Component\HttpKernel\Event\ViewEvent;
/**
* Contains all events thrown in the HttpKernel component.
*
@@ -39,17 +48,6 @@ final class KernelEvents
*/
public const EXCEPTION = 'kernel.exception';
/**
* The VIEW event occurs when the return value of a controller
* is not a Response instance.
*
* This event allows you to create a response for the return value of the
* controller.
*
* @Event("Symfony\Component\HttpKernel\Event\ViewEvent")
*/
public const VIEW = 'kernel.view';
/**
* The CONTROLLER event occurs once a controller was found for
* handling a request.
@@ -71,6 +69,17 @@ final class KernelEvents
*/
public const CONTROLLER_ARGUMENTS = 'kernel.controller_arguments';
/**
* The VIEW event occurs when the return value of a controller
* is not a Response instance.
*
* This event allows you to create a response for the return value of the
* controller.
*
* @Event("Symfony\Component\HttpKernel\Event\ViewEvent")
*/
public const VIEW = 'kernel.view';
/**
* The RESPONSE event occurs once a response was created for
* replying to a request.
@@ -82,6 +91,16 @@ final class KernelEvents
*/
public const RESPONSE = 'kernel.response';
/**
* The FINISH_REQUEST event occurs when a response was generated for a request.
*
* This event allows you to reset the global and environmental state of
* the application, when it was changed during the request.
*
* @Event("Symfony\Component\HttpKernel\Event\FinishRequestEvent")
*/
public const FINISH_REQUEST = 'kernel.finish_request';
/**
* The TERMINATE event occurs once a response was sent.
*
@@ -92,12 +111,18 @@ final class KernelEvents
public const TERMINATE = 'kernel.terminate';
/**
* The FINISH_REQUEST event occurs when a response was generated for a request.
* Event aliases.
*
* This event allows you to reset the global and environmental state of
* the application, when it was changed during the request.
*
* @Event("Symfony\Component\HttpKernel\Event\FinishRequestEvent")
* These aliases can be consumed by RegisterListenersPass.
*/
public const FINISH_REQUEST = 'kernel.finish_request';
public const ALIASES = [
ControllerArgumentsEvent::class => self::CONTROLLER_ARGUMENTS,
ControllerEvent::class => self::CONTROLLER,
ResponseEvent::class => self::RESPONSE,
FinishRequestEvent::class => self::FINISH_REQUEST,
RequestEvent::class => self::REQUEST,
ViewEvent::class => self::VIEW,
ExceptionEvent::class => self::EXCEPTION,
TerminateEvent::class => self::TERMINATE,
];
}

View File

@@ -20,9 +20,11 @@ use Symfony\Component\HttpKernel\Bundle\BundleInterface;
*
* It manages an environment made of application kernel and bundles.
*
* @author Fabien Potencier <fabien@symfony.com>
* @method string getBuildDir() Returns the build directory - not implementing it is deprecated since Symfony 5.2.
* This directory should be used to store build artifacts, and can be read-only at runtime.
* Caches written at runtime should be stored in the "cache directory" ({@see KernelInterface::getCacheDir()}).
*
* @method string getProjectDir() Gets the project dir (path of the project's composer file) - not defining it is deprecated since Symfony 4.2
* @author Fabien Potencier <fabien@symfony.com>
*/
interface KernelInterface extends HttpKernelInterface
{
@@ -60,13 +62,11 @@ interface KernelInterface extends HttpKernelInterface
/**
* Returns a bundle.
*
* @param string $name Bundle name
*
* @return BundleInterface A BundleInterface instance
*
* @throws \InvalidArgumentException when the bundle is not enabled
*/
public function getBundle($name);
public function getBundle(string $name);
/**
* Returns the file path for a given bundle resource.
@@ -80,23 +80,12 @@ interface KernelInterface extends HttpKernelInterface
* where BundleName is the name of the bundle
* and the remaining part is the relative path in the bundle.
*
* @param string $name A resource name to locate
*
* @return string|array The absolute path of the resource or an array if $first is false (array return value is deprecated)
* @return string The absolute path of the resource
*
* @throws \InvalidArgumentException if the file cannot be found or the name is not valid
* @throws \RuntimeException if the name contains invalid/unsafe characters
*/
public function locateResource($name/*, $dir = null, $first = true*/);
/**
* Gets the name of the kernel.
*
* @return string The kernel name
*
* @deprecated since Symfony 4.2
*/
public function getName();
public function locateResource(string $name);
/**
* Gets the environment.
@@ -113,13 +102,11 @@ interface KernelInterface extends HttpKernelInterface
public function isDebug();
/**
* Gets the application root dir (path of the project's Kernel class).
* Gets the project dir (path of the project's composer file).
*
* @return string The Kernel root dir
*
* @deprecated since Symfony 4.2
* @return string
*/
public function getRootDir();
public function getProjectDir();
/**
* Gets the current container.
@@ -138,6 +125,10 @@ interface KernelInterface extends HttpKernelInterface
/**
* Gets the cache directory.
*
* Since Symfony 5.2, the cache directory should be used for caches that are written at runtime.
* For caches and artifacts that can be warmed at compile-time and deployed as read-only,
* use the new "build directory" returned by the {@see getBuildDir()} method.
*
* @return string The cache directory
*/
public function getCacheDir();

View File

@@ -27,20 +27,16 @@ interface DebugLoggerInterface
* timestamp, message, priority, and priorityName.
* It can also have an optional context key containing an array.
*
* @param Request|null $request The request to get logs for
*
* @return array An array of logs
*/
public function getLogs(/* Request $request = null */);
public function getLogs(Request $request = null);
/**
* Returns the number of errors.
*
* @param Request|null $request The request to count logs for
*
* @return int The number of errors
*/
public function countErrors(/* Request $request = null */);
public function countErrors(Request $request = null);
/**
* Removes all log records.

View File

@@ -47,7 +47,7 @@ class FileProfilerStorage implements ProfilerStorageInterface
/**
* {@inheritdoc}
*/
public function find($ip, $url, $limit, $method, $start = null, $end = null, $statusCode = null): array
public function find(?string $ip, ?string $url, ?int $limit, ?string $method, int $start = null, int $end = null, string $statusCode = null): array
{
$file = $this->getIndexFilename();
@@ -113,7 +113,7 @@ class FileProfilerStorage implements ProfilerStorageInterface
/**
* {@inheritdoc}
*/
public function read($token): ?Profile
public function read(string $token): ?Profile
{
if (!$token || !file_exists($file = $this->getFilename($token))) {
return null;
@@ -200,11 +200,9 @@ class FileProfilerStorage implements ProfilerStorageInterface
/**
* Gets filename to store data, associated to the token.
*
* @param string $token
*
* @return string The profile filename
*/
protected function getFilename($token)
protected function getFilename(string $token)
{
// Uses 4 last characters, because first are mostly the same.
$folderA = substr($token, -2, 2);
@@ -270,7 +268,7 @@ class FileProfilerStorage implements ProfilerStorageInterface
return '' === $line ? null : $line;
}
protected function createProfileFromData($token, $data, $parent = null)
protected function createProfileFromData(string $token, array $data, Profile $parent = null)
{
$profile = new Profile($token);
$profile->setIp($data['ip']);

View File

@@ -48,12 +48,7 @@ class Profile
$this->token = $token;
}
/**
* Sets the token.
*
* @param string $token The token
*/
public function setToken($token)
public function setToken(string $token)
{
$this->token = $token;
}
@@ -106,12 +101,7 @@ class Profile
return $this->ip;
}
/**
* Sets the IP.
*
* @param string $ip
*/
public function setIp($ip)
public function setIp(?string $ip)
{
$this->ip = $ip;
}
@@ -126,7 +116,7 @@ class Profile
return $this->method;
}
public function setMethod($method)
public function setMethod(string $method)
{
$this->method = $method;
}
@@ -141,17 +131,12 @@ class Profile
return $this->url;
}
/**
* @param string $url
*/
public function setUrl($url)
public function setUrl(?string $url)
{
$this->url = $url;
}
/**
* Returns the time.
*
* @return int The time
*/
public function getTime()
@@ -163,18 +148,12 @@ class Profile
return $this->time;
}
/**
* @param int $time The time
*/
public function setTime($time)
public function setTime(int $time)
{
$this->time = $time;
}
/**
* @param int $statusCode
*/
public function setStatusCode($statusCode)
public function setStatusCode(int $statusCode)
{
$this->statusCode = $statusCode;
}
@@ -233,13 +212,11 @@ class Profile
/**
* Gets a Collector by name.
*
* @param string $name A collector name
*
* @return DataCollectorInterface A DataCollectorInterface instance
*
* @throws \InvalidArgumentException if the collector does not exist
*/
public function getCollector($name)
public function getCollector(string $name)
{
if (!isset($this->collectors[$name])) {
throw new \InvalidArgumentException(sprintf('Collector "%s" does not exist.', $name));
@@ -280,13 +257,9 @@ class Profile
}
/**
* Returns true if a Collector for the given name exists.
*
* @param string $name A collector name
*
* @return bool
*/
public function hasCollector($name)
public function hasCollector(string $name)
{
return isset($this->collectors[$name]);
}

View File

@@ -12,7 +12,6 @@
namespace Symfony\Component\HttpKernel\Profiler;
use Psr\Log\LoggerInterface;
use Symfony\Component\Debug\Exception\FatalThrowableError;
use Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -78,11 +77,9 @@ class Profiler implements ResetInterface
/**
* Loads the Profile for the given token.
*
* @param string $token A token
*
* @return Profile|null A Profile instance
*/
public function loadProfile($token)
public function loadProfile(string $token)
{
return $this->storage->read($token);
}
@@ -119,19 +116,15 @@ class Profiler implements ResetInterface
/**
* Finds profiler tokens for the given criteria.
*
* @param string $ip The IP
* @param string $url The URL
* @param string $limit The maximum number of tokens to return
* @param string $method The request method
* @param string $start The start date to search from
* @param string $end The end date to search to
* @param string $statusCode The request status code
* @param string|null $limit The maximum number of tokens to return
* @param string|null $start The start date to search from
* @param string|null $end The end date to search to
*
* @return array An array of tokens
*
* @see https://php.net/datetime.formats for the supported date/time formats
*/
public function find($ip, $url, $limit, $method, $start, $end, $statusCode = null)
public function find(?string $ip, ?string $url, ?string $limit, ?string $method, ?string $start, ?string $end, string $statusCode = null)
{
return $this->storage->find($ip, $url, $limit, $method, $this->getTimestamp($start), $this->getTimestamp($end), $statusCode);
}
@@ -139,14 +132,10 @@ class Profiler implements ResetInterface
/**
* Collects data for the given Response.
*
* @param \Throwable|null $exception
*
* @return Profile|null A Profile instance or null if the profiler is disabled
*/
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 (false === $this->enabled) {
return null;
}
@@ -168,14 +157,9 @@ class Profiler implements ResetInterface
$response->headers->set('X-Debug-Token', $profile->getToken());
$wrappedException = null;
foreach ($this->collectors as $collector) {
if (($e = $exception) instanceof \Error) {
$r = new \ReflectionMethod($collector, 'collect');
$e = 2 >= $r->getNumberOfParameters() || !($p = $r->getParameters()[2])->hasType() || \Exception::class !== $p->getType()->getName() ? $e : ($wrappedException ?? $wrappedException = new FatalThrowableError($e));
}
$collector->collect($request, $response, $exception);
$collector->collect($request, $response, $e);
// we need to clone for sub-requests
$profile->addCollector(clone $collector);
}
@@ -229,7 +213,7 @@ class Profiler implements ResetInterface
*
* @return bool
*/
public function has($name)
public function has(string $name)
{
return isset($this->collectors[$name]);
}
@@ -243,7 +227,7 @@ class Profiler implements ResetInterface
*
* @throws \InvalidArgumentException if the collector does not exist
*/
public function get($name)
public function get(string $name)
{
if (!isset($this->collectors[$name])) {
throw new \InvalidArgumentException(sprintf('Collector "%s" does not exist.', $name));

View File

@@ -20,7 +20,7 @@ namespace Symfony\Component\HttpKernel\Profiler;
* As the profiler must only be used on non-production servers, the file storage
* is more than enough and no other implementations will ever be supported.
*
* @internal since 4.2
* @internal
*
* @author Fabien Potencier <fabien@symfony.com>
*/
@@ -29,27 +29,22 @@ interface ProfilerStorageInterface
/**
* Finds profiler tokens for the given criteria.
*
* @param string $ip The IP
* @param string $url The URL
* @param string $limit The maximum number of tokens to return
* @param string $method The request method
* @param int|null $start The start date to search from
* @param int|null $end The end date to search to
* @param int|null $limit The maximum number of tokens to return
* @param int|null $start The start date to search from
* @param int|null $end The end date to search to
*
* @return array An array of tokens
*/
public function find($ip, $url, $limit, $method, $start = null, $end = null): array;
public function find(?string $ip, ?string $url, ?int $limit, ?string $method, int $start = null, int $end = null): array;
/**
* Reads data associated with the given token.
*
* The method returns false if the token does not exist in the storage.
*
* @param string $token A token
*
* @return Profile|null The profile associated with token
*/
public function read($token): ?Profile;
public function read(string $token): ?Profile;
/**
* Saves a Profile.

View File

@@ -21,10 +21,10 @@ interface RebootableInterface
/**
* Reboots a kernel.
*
* The getCacheDir() method of a rebootable kernel should not be called
* while building the container. Use the %kernel.cache_dir% parameter instead.
* The getBuildDir() method of a rebootable kernel should not be called
* while building the container. Use the %kernel.build_dir% parameter instead.
*
* @param string|null $warmupDir pass null to reboot in the regular cache directory
* @param string|null $warmupDir pass null to reboot in the regular build directory
*/
public function reboot($warmupDir);
public function reboot(?string $warmupDir);
}

View File

@@ -11,6 +11,8 @@
namespace Symfony\Component\HttpKernel;
use Symfony\Component\HttpFoundation\Request;
/**
* Signs URIs.
*
@@ -37,11 +39,9 @@ class UriSigner
* The given URI is signed by adding the query string parameter
* which value depends on the URI and the secret.
*
* @param string $uri A URI to sign
*
* @return string The signed URI
*/
public function sign($uri)
public function sign(string $uri)
{
$url = parse_url($uri);
if (isset($url['query'])) {
@@ -59,11 +59,9 @@ class UriSigner
/**
* Checks that a URI contains the correct hash.
*
* @param string $uri A signed URI
*
* @return bool True if the URI is signed correctly, false otherwise
*/
public function check($uri)
public function check(string $uri)
{
$url = parse_url($uri);
if (isset($url['query'])) {
@@ -82,6 +80,14 @@ class UriSigner
return hash_equals($this->computeHash($this->buildUrl($url, $params)), $hash);
}
public function checkRequest(Request $request): bool
{
$qs = ($qs = $request->server->get('QUERY_STRING')) ? '?'.$qs : '';
// we cannot use $request->getUri() here as we want to work with the original URI (no query string reordering)
return $this->check($request->getSchemeAndHttpHost().$request->getBaseUrl().$request->getPathInfo().$qs);
}
private function computeHash(string $uri): string
{
return base64_encode(hash_hmac('sha256', $uri, $this->secret, true));

View File

@@ -16,9 +16,10 @@
}
],
"require": {
"php": ">=7.1.3",
"symfony/error-handler": "^4.4",
"symfony/event-dispatcher": "^4.4",
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1",
"symfony/error-handler": "^4.4|^5.0",
"symfony/event-dispatcher": "^5.0",
"symfony/http-client-contracts": "^1.1|^2",
"symfony/http-foundation": "^4.4|^5.0",
"symfony/polyfill-ctype": "^1.8",
@@ -27,33 +28,40 @@
"psr/log": "~1.0"
},
"require-dev": {
"symfony/browser-kit": "^4.3|^5.0",
"symfony/config": "^3.4|^4.0|^5.0",
"symfony/console": "^3.4|^4.0",
"symfony/css-selector": "^3.4|^4.0|^5.0",
"symfony/dependency-injection": "^4.3|^5.0",
"symfony/dom-crawler": "^3.4|^4.0|^5.0",
"symfony/expression-language": "^3.4|^4.0|^5.0",
"symfony/finder": "^3.4|^4.0|^5.0",
"symfony/process": "^3.4|^4.0|^5.0",
"symfony/routing": "^3.4|^4.0|^5.0",
"symfony/stopwatch": "^3.4|^4.0|^5.0",
"symfony/templating": "^3.4|^4.0|^5.0",
"symfony/translation": "^4.2|^5.0",
"symfony/browser-kit": "^4.4|^5.0",
"symfony/config": "^5.0",
"symfony/console": "^4.4|^5.0",
"symfony/css-selector": "^4.4|^5.0",
"symfony/dependency-injection": "^5.1.8",
"symfony/dom-crawler": "^4.4|^5.0",
"symfony/expression-language": "^4.4|^5.0",
"symfony/finder": "^4.4|^5.0",
"symfony/process": "^4.4|^5.0",
"symfony/routing": "^4.4|^5.0",
"symfony/stopwatch": "^4.4|^5.0",
"symfony/translation": "^4.4|^5.0",
"symfony/translation-contracts": "^1.1|^2",
"psr/cache": "~1.0",
"twig/twig": "^1.34|^2.4|^3.0"
"twig/twig": "^2.4|^3.0"
},
"provide": {
"psr/log-implementation": "1.0"
},
"conflict": {
"symfony/browser-kit": "<4.3",
"symfony/config": "<3.4",
"symfony/console": ">=5",
"symfony/dependency-injection": "<4.3",
"symfony/translation": "<4.2",
"twig/twig": "<1.34|<2.4,>=2"
"symfony/browser-kit": "<4.4",
"symfony/cache": "<5.0",
"symfony/config": "<5.0",
"symfony/console": "<4.4",
"symfony/form": "<5.0",
"symfony/dependency-injection": "<5.1.8",
"symfony/doctrine-bridge": "<5.0",
"symfony/http-client": "<5.0",
"symfony/mailer": "<5.0",
"symfony/messenger": "<5.0",
"symfony/translation": "<5.0",
"symfony/twig-bridge": "<5.0",
"symfony/validator": "<5.0",
"twig/twig": "<2.4"
},
"suggest": {
"symfony/browser-kit": "",