first commit
This commit is contained in:
27
vendor/symfony/http-kernel/Attribute/AsController.php
vendored
Normal file
27
vendor/symfony/http-kernel/Attribute/AsController.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Attribute;
|
||||
|
||||
/**
|
||||
* Autoconfigures controllers as services by applying
|
||||
* the `controller.service_arguments` tag to them.
|
||||
*
|
||||
* This enables injecting services as method arguments in addition
|
||||
* to other conventional dependency injection strategies.
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_FUNCTION)]
|
||||
class AsController
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
}
|
24
vendor/symfony/http-kernel/Attribute/AsTargetedValueResolver.php
vendored
Normal file
24
vendor/symfony/http-kernel/Attribute/AsTargetedValueResolver.php
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Attribute;
|
||||
|
||||
/**
|
||||
* Service tag to autoconfigure targeted value resolvers.
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class AsTargetedValueResolver
|
||||
{
|
||||
public function __construct(
|
||||
public readonly ?string $name = null,
|
||||
) {
|
||||
}
|
||||
}
|
107
vendor/symfony/http-kernel/Attribute/Cache.php
vendored
Normal file
107
vendor/symfony/http-kernel/Attribute/Cache.php
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Attribute;
|
||||
|
||||
/**
|
||||
* Describes the default HTTP cache headers on controllers.
|
||||
* Headers defined in the Cache attribute are ignored if they are already set
|
||||
* by the controller.
|
||||
*
|
||||
* @see https://symfony.com/doc/current/http_cache.html#making-your-responses-http-cacheable
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_FUNCTION)]
|
||||
final class Cache
|
||||
{
|
||||
public function __construct(
|
||||
/**
|
||||
* The expiration date as a valid date for the strtotime() function.
|
||||
*/
|
||||
public ?string $expires = null,
|
||||
|
||||
/**
|
||||
* The number of seconds that the response is considered fresh by a private
|
||||
* cache like a web browser.
|
||||
*/
|
||||
public int|string|null $maxage = null,
|
||||
|
||||
/**
|
||||
* The number of seconds that the response is considered fresh by a public
|
||||
* cache like a reverse proxy cache.
|
||||
*/
|
||||
public int|string|null $smaxage = null,
|
||||
|
||||
/**
|
||||
* If true, the contents will be stored in a public cache and served to all
|
||||
* the next requests.
|
||||
*/
|
||||
public ?bool $public = null,
|
||||
|
||||
/**
|
||||
* If true, the response is not served stale by a cache in any circumstance
|
||||
* without first revalidating with the origin.
|
||||
*/
|
||||
public bool $mustRevalidate = false,
|
||||
|
||||
/**
|
||||
* Set "Vary" header.
|
||||
*
|
||||
* Example:
|
||||
* ['Accept-Encoding', 'User-Agent']
|
||||
*
|
||||
* @see https://symfony.com/doc/current/http_cache/cache_vary.html
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public array $vary = [],
|
||||
|
||||
/**
|
||||
* An expression to compute the Last-Modified HTTP header.
|
||||
*
|
||||
* The expression is evaluated by the ExpressionLanguage component, it
|
||||
* receives all the request attributes and the resolved controller arguments.
|
||||
*
|
||||
* The result of the expression must be a DateTimeInterface.
|
||||
*/
|
||||
public ?string $lastModified = null,
|
||||
|
||||
/**
|
||||
* An expression to compute the ETag HTTP header.
|
||||
*
|
||||
* The expression is evaluated by the ExpressionLanguage component, it
|
||||
* receives all the request attributes and the resolved controller arguments.
|
||||
*
|
||||
* The result must be a string that will be hashed.
|
||||
*/
|
||||
public ?string $etag = null,
|
||||
|
||||
/**
|
||||
* max-stale Cache-Control header
|
||||
* It can be expressed in seconds or with a relative time format (1 day, 2 weeks, ...).
|
||||
*/
|
||||
public int|string|null $maxStale = null,
|
||||
|
||||
/**
|
||||
* stale-while-revalidate Cache-Control header
|
||||
* It can be expressed in seconds or with a relative time format (1 day, 2 weeks, ...).
|
||||
*/
|
||||
public int|string|null $staleWhileRevalidate = null,
|
||||
|
||||
/**
|
||||
* stale-if-error Cache-Control header
|
||||
* It can be expressed in seconds or with a relative time format (1 day, 2 weeks, ...).
|
||||
*/
|
||||
public int|string|null $staleIfError = null,
|
||||
) {
|
||||
}
|
||||
}
|
29
vendor/symfony/http-kernel/Attribute/MapDateTime.php
vendored
Normal file
29
vendor/symfony/http-kernel/Attribute/MapDateTime.php
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Attribute;
|
||||
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\DateTimeValueResolver;
|
||||
|
||||
/**
|
||||
* Controller parameter tag to configure DateTime arguments.
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER)]
|
||||
class MapDateTime extends ValueResolver
|
||||
{
|
||||
public function __construct(
|
||||
public readonly ?string $format = null,
|
||||
bool $disabled = false,
|
||||
string $resolver = DateTimeValueResolver::class,
|
||||
) {
|
||||
parent::__construct($resolver, $disabled);
|
||||
}
|
||||
}
|
38
vendor/symfony/http-kernel/Attribute/MapQueryParameter.php
vendored
Normal file
38
vendor/symfony/http-kernel/Attribute/MapQueryParameter.php
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Attribute;
|
||||
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\QueryParameterValueResolver;
|
||||
|
||||
/**
|
||||
* Can be used to pass a query parameter to a controller argument.
|
||||
*
|
||||
* @author Ruud Kamphuis <ruud@ticketswap.com>
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER)]
|
||||
final class MapQueryParameter extends ValueResolver
|
||||
{
|
||||
/**
|
||||
* @see https://php.net/filter.filters.validate for filter, flags and options
|
||||
*
|
||||
* @param string|null $name The name of the query parameter. If null, the name of the argument in the controller will be used.
|
||||
*/
|
||||
public function __construct(
|
||||
public ?string $name = null,
|
||||
public ?int $filter = null,
|
||||
public int $flags = 0,
|
||||
public array $options = [],
|
||||
string $resolver = QueryParameterValueResolver::class,
|
||||
) {
|
||||
parent::__construct($resolver);
|
||||
}
|
||||
}
|
37
vendor/symfony/http-kernel/Attribute/MapQueryString.php
vendored
Normal file
37
vendor/symfony/http-kernel/Attribute/MapQueryString.php
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestPayloadValueResolver;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
use Symfony\Component\Validator\Constraints\GroupSequence;
|
||||
|
||||
/**
|
||||
* Controller parameter tag to map the query string of the request to typed object and validate it.
|
||||
*
|
||||
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER)]
|
||||
class MapQueryString extends ValueResolver
|
||||
{
|
||||
public ArgumentMetadata $metadata;
|
||||
|
||||
public function __construct(
|
||||
public readonly array $serializationContext = [],
|
||||
public readonly string|GroupSequence|array|null $validationGroups = null,
|
||||
string $resolver = RequestPayloadValueResolver::class,
|
||||
public readonly int $validationFailedStatusCode = Response::HTTP_NOT_FOUND,
|
||||
) {
|
||||
parent::__construct($resolver);
|
||||
}
|
||||
}
|
38
vendor/symfony/http-kernel/Attribute/MapRequestPayload.php
vendored
Normal file
38
vendor/symfony/http-kernel/Attribute/MapRequestPayload.php
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Attribute;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestPayloadValueResolver;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
use Symfony\Component\Validator\Constraints\GroupSequence;
|
||||
|
||||
/**
|
||||
* Controller parameter tag to map the request content to typed object and validate it.
|
||||
*
|
||||
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER)]
|
||||
class MapRequestPayload extends ValueResolver
|
||||
{
|
||||
public ArgumentMetadata $metadata;
|
||||
|
||||
public function __construct(
|
||||
public readonly array|string|null $acceptFormat = null,
|
||||
public readonly array $serializationContext = [],
|
||||
public readonly string|GroupSequence|array|null $validationGroups = null,
|
||||
string $resolver = RequestPayloadValueResolver::class,
|
||||
public readonly int $validationFailedStatusCode = Response::HTTP_UNPROCESSABLE_ENTITY,
|
||||
) {
|
||||
parent::__construct($resolver);
|
||||
}
|
||||
}
|
27
vendor/symfony/http-kernel/Attribute/ValueResolver.php
vendored
Normal file
27
vendor/symfony/http-kernel/Attribute/ValueResolver.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Attribute;
|
||||
|
||||
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PARAMETER | \Attribute::IS_REPEATABLE)]
|
||||
class ValueResolver
|
||||
{
|
||||
/**
|
||||
* @param class-string<ValueResolverInterface>|string $resolver
|
||||
*/
|
||||
public function __construct(
|
||||
public string $resolver,
|
||||
public bool $disabled = false,
|
||||
) {
|
||||
}
|
||||
}
|
28
vendor/symfony/http-kernel/Attribute/WithHttpStatus.php
vendored
Normal file
28
vendor/symfony/http-kernel/Attribute/WithHttpStatus.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Attribute;
|
||||
|
||||
/**
|
||||
* @author Dejan Angelov <angelovdejan@protonmail.com>
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class WithHttpStatus
|
||||
{
|
||||
/**
|
||||
* @param array<string, string> $headers
|
||||
*/
|
||||
public function __construct(
|
||||
public readonly int $statusCode,
|
||||
public readonly array $headers = [],
|
||||
) {
|
||||
}
|
||||
}
|
31
vendor/symfony/http-kernel/Attribute/WithLogLevel.php
vendored
Normal file
31
vendor/symfony/http-kernel/Attribute/WithLogLevel.php
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Attribute;
|
||||
|
||||
use Psr\Log\LogLevel;
|
||||
|
||||
/**
|
||||
* @author Dejan Angelov <angelovdejan@protonmail.com>
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
final class WithLogLevel
|
||||
{
|
||||
/**
|
||||
* @param LogLevel::* $level
|
||||
*/
|
||||
public function __construct(public readonly string $level)
|
||||
{
|
||||
if (!\defined('Psr\Log\LogLevel::'.strtoupper($this->level))) {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid log level "%s".', $this->level));
|
||||
}
|
||||
}
|
||||
}
|
61
vendor/symfony/http-kernel/Bundle/AbstractBundle.php
vendored
Normal file
61
vendor/symfony/http-kernel/Bundle/AbstractBundle.php
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Bundle;
|
||||
|
||||
use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Extension\ConfigurableExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
/**
|
||||
* A Bundle that provides configuration hooks.
|
||||
*
|
||||
* @author Yonel Ceruto <yonelceruto@gmail.com>
|
||||
*/
|
||||
abstract class AbstractBundle extends Bundle implements ConfigurableExtensionInterface
|
||||
{
|
||||
protected string $extensionAlias = '';
|
||||
|
||||
public function configure(DefinitionConfigurator $definition): void
|
||||
{
|
||||
}
|
||||
|
||||
public function prependExtension(ContainerConfigurator $container, ContainerBuilder $builder): void
|
||||
{
|
||||
}
|
||||
|
||||
public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
|
||||
{
|
||||
}
|
||||
|
||||
public function getContainerExtension(): ?ExtensionInterface
|
||||
{
|
||||
if ('' === $this->extensionAlias) {
|
||||
$this->extensionAlias = Container::underscore(preg_replace('/Bundle$/', '', $this->getName()));
|
||||
}
|
||||
|
||||
return $this->extension ??= new BundleExtension($this, $this->extensionAlias);
|
||||
}
|
||||
|
||||
public function getPath(): string
|
||||
{
|
||||
if (null === $this->path) {
|
||||
$reflected = new \ReflectionObject($this);
|
||||
// assume the modern directory structure by default
|
||||
$this->path = \dirname($reflected->getFileName(), 2);
|
||||
}
|
||||
|
||||
return $this->path;
|
||||
}
|
||||
}
|
160
vendor/symfony/http-kernel/Bundle/Bundle.php
vendored
Normal file
160
vendor/symfony/http-kernel/Bundle/Bundle.php
vendored
Normal file
@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Bundle;
|
||||
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
|
||||
|
||||
/**
|
||||
* An implementation of BundleInterface that adds a few conventions for DependencyInjection extensions.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
abstract class Bundle implements BundleInterface
|
||||
{
|
||||
protected $name;
|
||||
protected $extension;
|
||||
protected $path;
|
||||
private string $namespace;
|
||||
|
||||
/**
|
||||
* @var ContainerInterface|null
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* This method can be overridden to register compilation passes,
|
||||
* other extensions, ...
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function build(ContainerBuilder $container)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bundle's container extension.
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function getContainerExtension(): ?ExtensionInterface
|
||||
{
|
||||
if (!isset($this->extension)) {
|
||||
$extension = $this->createContainerExtension();
|
||||
|
||||
if (null !== $extension) {
|
||||
if (!$extension instanceof ExtensionInterface) {
|
||||
throw new \LogicException(sprintf('Extension "%s" must implement Symfony\Component\DependencyInjection\Extension\ExtensionInterface.', get_debug_type($extension)));
|
||||
}
|
||||
|
||||
// check naming convention
|
||||
$basename = preg_replace('/Bundle$/', '', $this->getName());
|
||||
$expectedAlias = Container::underscore($basename);
|
||||
|
||||
if ($expectedAlias != $extension->getAlias()) {
|
||||
throw new \LogicException(sprintf('Users will expect the alias of the default extension of a bundle to be the underscored version of the bundle name ("%s"). You can override "Bundle::getContainerExtension()" if you want to use "%s" or another alias.', $expectedAlias, $extension->getAlias()));
|
||||
}
|
||||
|
||||
$this->extension = $extension;
|
||||
} else {
|
||||
$this->extension = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->extension ?: null;
|
||||
}
|
||||
|
||||
public function getNamespace(): string
|
||||
{
|
||||
if (!isset($this->namespace)) {
|
||||
$this->parseClassName();
|
||||
}
|
||||
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
public function getPath(): string
|
||||
{
|
||||
if (!isset($this->path)) {
|
||||
$reflected = new \ReflectionObject($this);
|
||||
$this->path = \dirname($reflected->getFileName());
|
||||
}
|
||||
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bundle name (the class short name).
|
||||
*/
|
||||
final public function getName(): string
|
||||
{
|
||||
if (!isset($this->name)) {
|
||||
$this->parseClassName();
|
||||
}
|
||||
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function registerCommands(Application $application)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bundle's container extension class.
|
||||
*/
|
||||
protected function getContainerExtensionClass(): string
|
||||
{
|
||||
$basename = preg_replace('/Bundle$/', '', $this->getName());
|
||||
|
||||
return $this->getNamespace().'\\DependencyInjection\\'.$basename.'Extension';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the bundle's container extension.
|
||||
*/
|
||||
protected function createContainerExtension(): ?ExtensionInterface
|
||||
{
|
||||
return class_exists($class = $this->getContainerExtensionClass()) ? new $class() : null;
|
||||
}
|
||||
|
||||
private function parseClassName(): void
|
||||
{
|
||||
$pos = strrpos(static::class, '\\');
|
||||
$this->namespace = false === $pos ? '' : substr(static::class, 0, $pos);
|
||||
$this->name ??= false === $pos ? static::class : substr(static::class, $pos + 1);
|
||||
}
|
||||
|
||||
public function setContainer(?ContainerInterface $container): void
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
}
|
67
vendor/symfony/http-kernel/Bundle/BundleExtension.php
vendored
Normal file
67
vendor/symfony/http-kernel/Bundle/BundleExtension.php
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Bundle;
|
||||
|
||||
use Symfony\Component\Config\Definition\Configuration;
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Extension\ConfigurableExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Extension\Extension;
|
||||
use Symfony\Component\DependencyInjection\Extension\ExtensionTrait;
|
||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
/**
|
||||
* @author Yonel Ceruto <yonelceruto@gmail.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class BundleExtension extends Extension implements PrependExtensionInterface
|
||||
{
|
||||
use ExtensionTrait;
|
||||
|
||||
public function __construct(
|
||||
private ConfigurableExtensionInterface $subject,
|
||||
private string $alias,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getConfiguration(array $config, ContainerBuilder $container): ?ConfigurationInterface
|
||||
{
|
||||
return new Configuration($this->subject, $container, $this->getAlias());
|
||||
}
|
||||
|
||||
public function getAlias(): string
|
||||
{
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
public function prepend(ContainerBuilder $container): void
|
||||
{
|
||||
$callback = function (ContainerConfigurator $configurator) use ($container) {
|
||||
$this->subject->prependExtension($configurator, $container);
|
||||
};
|
||||
|
||||
$this->executeConfiguratorCallback($container, $callback, $this->subject);
|
||||
}
|
||||
|
||||
public function load(array $configs, ContainerBuilder $container): void
|
||||
{
|
||||
$config = $this->processConfiguration($this->getConfiguration([], $container), $configs);
|
||||
|
||||
$callback = function (ContainerConfigurator $configurator) use ($config, $container) {
|
||||
$this->subject->loadExtension($config, $configurator, $container);
|
||||
};
|
||||
|
||||
$this->executeConfiguratorCallback($container, $callback, $this->subject);
|
||||
}
|
||||
}
|
74
vendor/symfony/http-kernel/Bundle/BundleInterface.php
vendored
Normal file
74
vendor/symfony/http-kernel/Bundle/BundleInterface.php
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Bundle;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
|
||||
|
||||
/**
|
||||
* BundleInterface.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface BundleInterface
|
||||
{
|
||||
/**
|
||||
* Boots the Bundle.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot();
|
||||
|
||||
/**
|
||||
* Shutdowns the Bundle.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function shutdown();
|
||||
|
||||
/**
|
||||
* Builds the bundle.
|
||||
*
|
||||
* It is only ever called once when the cache is empty.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function build(ContainerBuilder $container);
|
||||
|
||||
/**
|
||||
* Returns the container extension that should be implicitly loaded.
|
||||
*/
|
||||
public function getContainerExtension(): ?ExtensionInterface;
|
||||
|
||||
/**
|
||||
* Returns the bundle name (the class short name).
|
||||
*/
|
||||
public function getName(): string;
|
||||
|
||||
/**
|
||||
* Gets the Bundle namespace.
|
||||
*/
|
||||
public function getNamespace(): string;
|
||||
|
||||
/**
|
||||
* Gets the Bundle directory path.
|
||||
*
|
||||
* The path should always be returned as a Unix path (with /).
|
||||
*/
|
||||
public function getPath(): string;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setContainer(?ContainerInterface $container);
|
||||
}
|
382
vendor/symfony/http-kernel/CHANGELOG.md
vendored
Normal file
382
vendor/symfony/http-kernel/CHANGELOG.md
vendored
Normal file
@ -0,0 +1,382 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
6.4
|
||||
---
|
||||
|
||||
* Support backed enums in #[MapQueryParameter]
|
||||
* `BundleInterface` no longer extends `ContainerAwareInterface`
|
||||
* Add optional `$className` parameter to `ControllerEvent::getAttributes()`
|
||||
* Add native return types to `TraceableEventDispatcher` and to `MergeExtensionConfigurationPass`
|
||||
* Add argument `$validationFailedStatusCode` to `#[MapQueryString]` and `#[MapRequestPayload]`
|
||||
* Add argument `$debug` to `Logger`
|
||||
* Add class `DebugLoggerConfigurator`
|
||||
* Add parameters `kernel.runtime_mode` and `kernel.runtime_mode.*`, all set from env var `APP_RUNTIME_MODE`
|
||||
* Deprecate `Kernel::stripComments()`
|
||||
* Support the `!` character at the beginning of a string as a negation operator in the url filter of the profiler
|
||||
* Deprecate `UriSigner`, use `UriSigner` from the HttpFoundation component instead
|
||||
* Deprecate `FileLinkFormatter`, use `FileLinkFormatter` from the ErrorHandler component instead
|
||||
* Add argument `$buildDir` to `WarmableInterface`
|
||||
* Add argument `$filter` to `Profiler::find()` and `FileProfilerStorage::find()`
|
||||
* Add `ControllerResolver::allowControllers()` to define which callables are legit controllers when the `_check_controller_is_allowed` request attribute is set
|
||||
|
||||
6.3
|
||||
---
|
||||
|
||||
* Deprecate parameters `container.dumper.inline_factories` and `container.dumper.inline_class_loader`, use `.container.dumper.inline_factories` and `.container.dumper.inline_class_loader` instead
|
||||
* `FileProfilerStorage` removes profiles automatically after two days
|
||||
* Add `#[WithHttpStatus]` for defining status codes for exceptions
|
||||
* Use an instance of `Psr\Clock\ClockInterface` to generate the current date time in `DateTimeValueResolver`
|
||||
* Add `#[WithLogLevel]` for defining log levels for exceptions
|
||||
* Add `skip_response_headers` to the `HttpCache` options
|
||||
* Introduce targeted value resolvers with `#[ValueResolver]` and `#[AsTargetedValueResolver]`
|
||||
* Add `#[MapRequestPayload]` to map and validate request payload from `Request::getContent()` or `Request::$request->all()` to typed objects
|
||||
* Add `#[MapQueryString]` to map and validate request query string from `Request::$query->all()` to typed objects
|
||||
* Add `#[MapQueryParameter]` to map and validate individual query parameters to controller arguments
|
||||
* Collect data from every event dispatcher
|
||||
|
||||
6.2
|
||||
---
|
||||
|
||||
* Add constructor argument `bool $handleAllThrowable` to `HttpKernel`
|
||||
* Add `ControllerEvent::getAttributes()` to handle attributes on controllers
|
||||
* Add `#[Cache]` to describe the default HTTP cache headers on controllers
|
||||
* Add `absolute_uri` option to surrogate fragment renderers
|
||||
* Add `ValueResolverInterface` and deprecate `ArgumentValueResolverInterface`
|
||||
* Add argument `$reflector` to `ArgumentResolverInterface` and `ArgumentMetadataFactoryInterface`
|
||||
* Deprecate calling `ConfigDataCollector::setKernel()`, `RouterListener::setCurrentRequest()` without arguments
|
||||
|
||||
6.1
|
||||
---
|
||||
|
||||
* Add `BackedEnumValueResolver` to resolve backed enum cases from request attributes in controller arguments
|
||||
* Add `DateTimeValueResolver` to resolve request attributes into DateTime objects in controller arguments
|
||||
* Deprecate StreamedResponseListener, it's not needed anymore
|
||||
* Add `Profiler::isEnabled()` so collaborating collector services may elect to omit themselves
|
||||
* Add the `UidValueResolver` argument value resolver
|
||||
* Add `AbstractBundle` class for DI configuration/definition on a single file
|
||||
* Update the path of a bundle placed in the `src/` directory to the parent directory when `AbstractBundle` is used
|
||||
|
||||
6.0
|
||||
---
|
||||
|
||||
* Remove `ArgumentInterface`
|
||||
* Remove `ArgumentMetadata::getAttribute()`, use `getAttributes()` instead
|
||||
* Remove support for returning a `ContainerBuilder` from `KernelInterface::registerContainerConfiguration()`
|
||||
* Remove `KernelEvent::isMasterRequest()`, use `isMainRequest()` instead
|
||||
* Remove support for `service:action` syntax to reference controllers, use `serviceOrFqcn::method` instead
|
||||
|
||||
5.4
|
||||
---
|
||||
|
||||
* Add the ability to enable the profiler using a request query parameter, body parameter or attribute
|
||||
* Deprecate `AbstractTestSessionListener` and `TestSessionListener`, use `AbstractSessionListener` and `SessionListener` instead
|
||||
* Deprecate the `fileLinkFormat` parameter of `DebugHandlersListener`
|
||||
* Add support for configuring log level, and status code by exception class
|
||||
* Allow ignoring "kernel.reset" methods that don't exist with "on_invalid" attribute
|
||||
|
||||
5.3
|
||||
---
|
||||
|
||||
* Deprecate `ArgumentInterface`
|
||||
* Add `ArgumentMetadata::getAttributes()`
|
||||
* Deprecate `ArgumentMetadata::getAttribute()`, use `getAttributes()` instead
|
||||
* Mark the class `Symfony\Component\HttpKernel\EventListener\DebugHandlersListener` as internal
|
||||
* Deprecate returning a `ContainerBuilder` from `KernelInterface::registerContainerConfiguration()`
|
||||
* Deprecate `HttpKernelInterface::MASTER_REQUEST` and add `HttpKernelInterface::MAIN_REQUEST` as replacement
|
||||
* Deprecate `KernelEvent::isMasterRequest()` and add `isMainRequest()` as replacement
|
||||
* Add `#[AsController]` attribute for declaring standalone controllers on PHP 8
|
||||
* Add `FragmentUriGeneratorInterface` and `FragmentUriGenerator` to generate the URI of a fragment
|
||||
|
||||
5.2.0
|
||||
-----
|
||||
|
||||
* added session usage
|
||||
* made the public `http_cache` service handle requests when available
|
||||
* allowed enabling trusted hosts and proxies using new `kernel.trusted_hosts`,
|
||||
`kernel.trusted_proxies` and `kernel.trusted_headers` parameters
|
||||
* content of request parameter `_password` is now also hidden
|
||||
in the request profiler raw content section
|
||||
* Allowed adding attributes on controller arguments that will be passed to argument resolvers.
|
||||
* kernels implementing the `ExtensionInterface` will now be auto-registered to the container
|
||||
* added parameter `kernel.runtime_environment`, defined as `%env(default:kernel.environment:APP_RUNTIME_ENV)%`
|
||||
* do not set a default `Accept` HTTP header when using `HttpKernelBrowser`
|
||||
|
||||
5.1.0
|
||||
-----
|
||||
|
||||
* allowed to use a specific logger channel for deprecations
|
||||
* made `WarmableInterface::warmUp()` return a list of classes or files to preload on PHP 7.4+;
|
||||
not returning an array is deprecated
|
||||
* made kernels implementing `WarmableInterface` be part of the cache warmup stage
|
||||
* deprecated support for `service:action` syntax to reference controllers, use `serviceOrFqcn::method` instead
|
||||
* allowed using public aliases to reference controllers
|
||||
* added session usage reporting when the `_stateless` attribute of the request is set to `true`
|
||||
* added `AbstractSessionListener::onSessionUsage()` to report when the session is used while a request is stateless
|
||||
|
||||
5.0.0
|
||||
-----
|
||||
|
||||
* removed support for getting the container from a non-booted kernel
|
||||
* removed the first and second constructor argument of `ConfigDataCollector`
|
||||
* removed `ConfigDataCollector::getApplicationName()`
|
||||
* removed `ConfigDataCollector::getApplicationVersion()`
|
||||
* removed support for `Symfony\Component\Templating\EngineInterface` in `HIncludeFragmentRenderer`, use a `Twig\Environment` only
|
||||
* removed `TranslatorListener` in favor of `LocaleAwareListener`
|
||||
* removed `getRootDir()` and `getName()` from `Kernel` and `KernelInterface`
|
||||
* removed `FilterControllerArgumentsEvent`, use `ControllerArgumentsEvent` instead
|
||||
* removed `FilterControllerEvent`, use `ControllerEvent` instead
|
||||
* removed `FilterResponseEvent`, use `ResponseEvent` instead
|
||||
* removed `GetResponseEvent`, use `RequestEvent` instead
|
||||
* removed `GetResponseForControllerResultEvent`, use `ViewEvent` instead
|
||||
* removed `GetResponseForExceptionEvent`, use `ExceptionEvent` instead
|
||||
* removed `PostResponseEvent`, use `TerminateEvent` instead
|
||||
* removed `SaveSessionListener` in favor of `AbstractSessionListener`
|
||||
* removed `Client`, use `HttpKernelBrowser` instead
|
||||
* added method `getProjectDir()` to `KernelInterface`
|
||||
* removed methods `serialize` and `unserialize` from `DataCollector`, store the serialized state in the data property instead
|
||||
* made `ProfilerStorageInterface` internal
|
||||
* removed the second and third argument of `KernelInterface::locateResource`
|
||||
* removed the second and third argument of `FileLocator::__construct`
|
||||
* removed loading resources from `%kernel.root_dir%/Resources` and `%kernel.root_dir%` as
|
||||
fallback directories.
|
||||
* removed class `ExceptionListener`, use `ErrorListener` instead
|
||||
|
||||
4.4.0
|
||||
-----
|
||||
|
||||
* The `DebugHandlersListener` class has been marked as `final`
|
||||
* Added new Bundle directory convention consistent with standard skeletons
|
||||
* Deprecated the second and third argument of `KernelInterface::locateResource`
|
||||
* Deprecated the second and third argument of `FileLocator::__construct`
|
||||
* Deprecated loading resources from `%kernel.root_dir%/Resources` and `%kernel.root_dir%` as
|
||||
fallback directories. Resources like service definitions are usually loaded relative to the
|
||||
current directory or with a glob pattern. The fallback directories have never been advocated
|
||||
so you likely do not use those in any app based on the SF Standard or Flex edition.
|
||||
* Marked all dispatched event classes as `@final`
|
||||
* Added `ErrorController` to enable the preview and error rendering mechanism
|
||||
* Getting the container from a non-booted kernel is deprecated.
|
||||
* Marked the `AjaxDataCollector`, `ConfigDataCollector`, `EventDataCollector`,
|
||||
`ExceptionDataCollector`, `LoggerDataCollector`, `MemoryDataCollector`,
|
||||
`RequestDataCollector` and `TimeDataCollector` classes as `@final`.
|
||||
* Marked the `RouterDataCollector::collect()` method as `@final`.
|
||||
* The `DataCollectorInterface::collect()` and `Profiler::collect()` methods third parameter signature
|
||||
will be `\Throwable $exception = null` instead of `\Exception $exception = null` in Symfony 5.0.
|
||||
* Deprecated methods `ExceptionEvent::get/setException()`, use `get/setThrowable()` instead
|
||||
* Deprecated class `ExceptionListener`, use `ErrorListener` instead
|
||||
|
||||
4.3.0
|
||||
-----
|
||||
|
||||
* renamed `Client` to `HttpKernelBrowser`
|
||||
* `KernelInterface` doesn't extend `Serializable` anymore
|
||||
* deprecated the `Kernel::serialize()` and `unserialize()` methods
|
||||
* increased the priority of `Symfony\Component\HttpKernel\EventListener\AddRequestFormatsListener`
|
||||
* made `Symfony\Component\HttpKernel\EventListener\LocaleListener` set the default locale early
|
||||
* deprecated `TranslatorListener` in favor of `LocaleAwareListener`
|
||||
* added the registration of all `LocaleAwareInterface` implementations into the `LocaleAwareListener`
|
||||
* made `FileLinkFormatter` final and not implement `Serializable` anymore
|
||||
* the base `DataCollector` doesn't implement `Serializable` anymore, you should
|
||||
store all the serialized state in the data property instead
|
||||
* `DumpDataCollector` has been marked as `final`
|
||||
* added an event listener to prevent search engines from indexing applications in debug mode.
|
||||
* renamed `FilterControllerArgumentsEvent` to `ControllerArgumentsEvent`
|
||||
* renamed `FilterControllerEvent` to `ControllerEvent`
|
||||
* renamed `FilterResponseEvent` to `ResponseEvent`
|
||||
* renamed `GetResponseEvent` to `RequestEvent`
|
||||
* renamed `GetResponseForControllerResultEvent` to `ViewEvent`
|
||||
* renamed `GetResponseForExceptionEvent` to `ExceptionEvent`
|
||||
* renamed `PostResponseEvent` to `TerminateEvent`
|
||||
* added `HttpClientKernel` for handling requests with an `HttpClientInterface` instance
|
||||
* added `trace_header` and `trace_level` configuration options to `HttpCache`
|
||||
|
||||
4.2.0
|
||||
-----
|
||||
|
||||
* deprecated `KernelInterface::getRootDir()` and the `kernel.root_dir` parameter
|
||||
* deprecated `KernelInterface::getName()` and the `kernel.name` parameter
|
||||
* deprecated the first and second constructor argument of `ConfigDataCollector`
|
||||
* deprecated `ConfigDataCollector::getApplicationName()`
|
||||
* deprecated `ConfigDataCollector::getApplicationVersion()`
|
||||
|
||||
4.1.0
|
||||
-----
|
||||
|
||||
* added orphaned events support to `EventDataCollector`
|
||||
* `ExceptionListener` now logs exceptions at priority `0` (previously logged at `-128`)
|
||||
* Added support for using `service::method` to reference controllers, making it consistent with other cases. It is recommended over the `service:action` syntax with a single colon, which will be deprecated in the future.
|
||||
* Added the ability to profile individual argument value resolvers via the
|
||||
`Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver`
|
||||
|
||||
4.0.0
|
||||
-----
|
||||
|
||||
* removed the `DataCollector::varToString()` method, use `DataCollector::cloneVar()`
|
||||
instead
|
||||
* using the `DataCollector::cloneVar()` method requires the VarDumper component
|
||||
* removed the `ValueExporter` class
|
||||
* removed `ControllerResolverInterface::getArguments()`
|
||||
* removed `TraceableControllerResolver::getArguments()`
|
||||
* removed `ControllerResolver::getArguments()` and the ability to resolve arguments
|
||||
* removed the `argument_resolver` service dependency from the `debug.controller_resolver`
|
||||
* removed `LazyLoadingFragmentHandler::addRendererService()`
|
||||
* removed `Psr6CacheClearer::addPool()`
|
||||
* removed `Extension::addClassesToCompile()` and `Extension::getClassesToCompile()`
|
||||
* removed `Kernel::loadClassCache()`, `Kernel::doLoadClassCache()`, `Kernel::setClassCache()`,
|
||||
and `Kernel::getEnvParameters()`
|
||||
* support for the `X-Status-Code` when handling exceptions in the `HttpKernel`
|
||||
has been dropped, use the `HttpKernel::allowCustomResponseCode()` method
|
||||
instead
|
||||
* removed convention-based commands registration
|
||||
* removed the `ChainCacheClearer::add()` method
|
||||
* removed the `CacheaWarmerAggregate::add()` and `setWarmers()` methods
|
||||
* made `CacheWarmerAggregate` and `ChainCacheClearer` classes final
|
||||
|
||||
3.4.0
|
||||
-----
|
||||
|
||||
* added a minimalist PSR-3 `Logger` class that writes in `stderr`
|
||||
* made kernels implementing `CompilerPassInterface` able to process the container
|
||||
* deprecated bundle inheritance
|
||||
* added `RebootableInterface` and implemented it in `Kernel`
|
||||
* deprecated commands auto registration
|
||||
* deprecated `EnvParametersResource`
|
||||
* added `Symfony\Component\HttpKernel\Client::catchExceptions()`
|
||||
* deprecated the `ChainCacheClearer::add()` method
|
||||
* deprecated the `CacheaWarmerAggregate::add()` and `setWarmers()` methods
|
||||
* made `CacheWarmerAggregate` and `ChainCacheClearer` classes final
|
||||
* added the possibility to reset the profiler to its initial state
|
||||
* deprecated data collectors without a `reset()` method
|
||||
* deprecated implementing `DebugLoggerInterface` without a `clear()` method
|
||||
|
||||
3.3.0
|
||||
-----
|
||||
|
||||
* added `kernel.project_dir` and `Kernel::getProjectDir()`
|
||||
* deprecated `kernel.root_dir` and `Kernel::getRootDir()`
|
||||
* deprecated `Kernel::getEnvParameters()`
|
||||
* deprecated the special `SYMFONY__` environment variables
|
||||
* added the possibility to change the query string parameter used by `UriSigner`
|
||||
* deprecated `LazyLoadingFragmentHandler::addRendererService()`
|
||||
* deprecated `Extension::addClassesToCompile()` and `Extension::getClassesToCompile()`
|
||||
* deprecated `Psr6CacheClearer::addPool()`
|
||||
|
||||
3.2.0
|
||||
-----
|
||||
|
||||
* deprecated `DataCollector::varToString()`, use `cloneVar()` instead
|
||||
* changed surrogate capability name in `AbstractSurrogate::addSurrogateCapability` to 'symfony'
|
||||
* Added `ControllerArgumentValueResolverPass`
|
||||
|
||||
3.1.0
|
||||
-----
|
||||
* deprecated passing objects as URI attributes to the ESI and SSI renderers
|
||||
* deprecated `ControllerResolver::getArguments()`
|
||||
* added `Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface`
|
||||
* added `Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface` as argument to `HttpKernel`
|
||||
* added `Symfony\Component\HttpKernel\Controller\ArgumentResolver`
|
||||
* added `Symfony\Component\HttpKernel\DataCollector\RequestDataCollector::getMethod()`
|
||||
* added `Symfony\Component\HttpKernel\DataCollector\RequestDataCollector::getRedirect()`
|
||||
* added the `kernel.controller_arguments` event, triggered after controller arguments have been resolved
|
||||
|
||||
3.0.0
|
||||
-----
|
||||
|
||||
* removed `Symfony\Component\HttpKernel\Kernel::init()`
|
||||
* removed `Symfony\Component\HttpKernel\Kernel::isClassInActiveBundle()` and `Symfony\Component\HttpKernel\KernelInterface::isClassInActiveBundle()`
|
||||
* removed `Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher::setProfiler()`
|
||||
* removed `Symfony\Component\HttpKernel\EventListener\FragmentListener::getLocalIpAddresses()`
|
||||
* removed `Symfony\Component\HttpKernel\EventListener\LocaleListener::setRequest()`
|
||||
* removed `Symfony\Component\HttpKernel\EventListener\RouterListener::setRequest()`
|
||||
* removed `Symfony\Component\HttpKernel\EventListener\ProfilerListener::onKernelRequest()`
|
||||
* removed `Symfony\Component\HttpKernel\Fragment\FragmentHandler::setRequest()`
|
||||
* removed `Symfony\Component\HttpKernel\HttpCache\Esi::hasSurrogateEsiCapability()`
|
||||
* removed `Symfony\Component\HttpKernel\HttpCache\Esi::addSurrogateEsiCapability()`
|
||||
* removed `Symfony\Component\HttpKernel\HttpCache\Esi::needsEsiParsing()`
|
||||
* removed `Symfony\Component\HttpKernel\HttpCache\HttpCache::getEsi()`
|
||||
* removed `Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel`
|
||||
* removed `Symfony\Component\HttpKernel\DependencyInjection\RegisterListenersPass`
|
||||
* removed `Symfony\Component\HttpKernel\EventListener\ErrorsLoggerListener`
|
||||
* removed `Symfony\Component\HttpKernel\EventListener\EsiListener`
|
||||
* removed `Symfony\Component\HttpKernel\HttpCache\EsiResponseCacheStrategy`
|
||||
* removed `Symfony\Component\HttpKernel\HttpCache\EsiResponseCacheStrategyInterface`
|
||||
* removed `Symfony\Component\HttpKernel\Log\LoggerInterface`
|
||||
* removed `Symfony\Component\HttpKernel\Log\NullLogger`
|
||||
* removed `Symfony\Component\HttpKernel\Profiler::import()`
|
||||
* removed `Symfony\Component\HttpKernel\Profiler::export()`
|
||||
|
||||
2.8.0
|
||||
-----
|
||||
|
||||
* deprecated `Profiler::import` and `Profiler::export`
|
||||
|
||||
2.7.0
|
||||
-----
|
||||
|
||||
* added the HTTP status code to profiles
|
||||
|
||||
2.6.0
|
||||
-----
|
||||
|
||||
* deprecated `Symfony\Component\HttpKernel\EventListener\ErrorsLoggerListener`, use `Symfony\Component\HttpKernel\EventListener\DebugHandlersListener` instead
|
||||
* deprecated unused method `Symfony\Component\HttpKernel\Kernel::isClassInActiveBundle` and `Symfony\Component\HttpKernel\KernelInterface::isClassInActiveBundle`
|
||||
|
||||
2.5.0
|
||||
-----
|
||||
|
||||
* deprecated `Symfony\Component\HttpKernel\DependencyInjection\RegisterListenersPass`, use `Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass` instead
|
||||
|
||||
2.4.0
|
||||
-----
|
||||
|
||||
* added event listeners for the session
|
||||
* added the KernelEvents::FINISH_REQUEST event
|
||||
|
||||
2.3.0
|
||||
-----
|
||||
|
||||
* [BC BREAK] renamed `Symfony\Component\HttpKernel\EventListener\DeprecationLoggerListener` to `Symfony\Component\HttpKernel\EventListener\ErrorsLoggerListener` and changed its constructor
|
||||
* deprecated `Symfony\Component\HttpKernel\Debug\ErrorHandler`, `Symfony\Component\HttpKernel\Debug\ExceptionHandler`,
|
||||
`Symfony\Component\HttpKernel\Exception\FatalErrorException` and `Symfony\Component\HttpKernel\Exception\FlattenException`
|
||||
* deprecated `Symfony\Component\HttpKernel\Kernel::init()`
|
||||
* added the possibility to specify an id an extra attributes to hinclude tags
|
||||
* added the collect of data if a controller is a Closure in the Request collector
|
||||
* pass exceptions from the ExceptionListener to the logger using the logging context to allow for more
|
||||
detailed messages
|
||||
|
||||
2.2.0
|
||||
-----
|
||||
|
||||
* [BC BREAK] the path info for sub-request is now always _fragment (or whatever you configured instead of the default)
|
||||
* added Symfony\Component\HttpKernel\EventListener\FragmentListener
|
||||
* added Symfony\Component\HttpKernel\UriSigner
|
||||
* added Symfony\Component\HttpKernel\FragmentRenderer and rendering strategies (in Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface)
|
||||
* added Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel
|
||||
* added ControllerReference to create reference of Controllers (used in the FragmentRenderer class)
|
||||
* [BC BREAK] renamed TimeDataCollector::getTotalTime() to
|
||||
TimeDataCollector::getDuration()
|
||||
* updated the MemoryDataCollector to include the memory used in the
|
||||
kernel.terminate event listeners
|
||||
* moved the Stopwatch classes to a new component
|
||||
* added TraceableControllerResolver
|
||||
* added TraceableEventDispatcher (removed ContainerAwareTraceableEventDispatcher)
|
||||
* added support for WinCache opcode cache in ConfigDataCollector
|
||||
|
||||
2.1.0
|
||||
-----
|
||||
|
||||
* [BC BREAK] the charset is now configured via the Kernel::getCharset() method
|
||||
* [BC BREAK] the current locale for the user is not stored anymore in the session
|
||||
* added the HTTP method to the profiler storage
|
||||
* updated all listeners to implement EventSubscriberInterface
|
||||
* added TimeDataCollector
|
||||
* added ContainerAwareTraceableEventDispatcher
|
||||
* moved TraceableEventDispatcherInterface to the EventDispatcher component
|
||||
* added RouterListener, LocaleListener, and StreamedResponseListener
|
||||
* added CacheClearerInterface (and ChainCacheClearer)
|
||||
* added a kernel.terminate event (via TerminableInterface and PostResponseEvent)
|
||||
* added a Stopwatch class
|
||||
* added WarmableInterface
|
||||
* improved extensibility between bundles
|
||||
* added profiler storages for Memcache(d), File-based, MongoDB, Redis
|
||||
* moved Filesystem class to its own component
|
27
vendor/symfony/http-kernel/CacheClearer/CacheClearerInterface.php
vendored
Normal file
27
vendor/symfony/http-kernel/CacheClearer/CacheClearerInterface.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\CacheClearer;
|
||||
|
||||
/**
|
||||
* CacheClearerInterface.
|
||||
*
|
||||
* @author Dustin Dobervich <ddobervich@gmail.com>
|
||||
*/
|
||||
interface CacheClearerInterface
|
||||
{
|
||||
/**
|
||||
* Clears any caches necessary.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function clear(string $cacheDir);
|
||||
}
|
39
vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php
vendored
Normal file
39
vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
<?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\CacheClearer;
|
||||
|
||||
/**
|
||||
* ChainCacheClearer.
|
||||
*
|
||||
* @author Dustin Dobervich <ddobervich@gmail.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class ChainCacheClearer implements CacheClearerInterface
|
||||
{
|
||||
private iterable $clearers;
|
||||
|
||||
/**
|
||||
* @param iterable<mixed, CacheClearerInterface> $clearers
|
||||
*/
|
||||
public function __construct(iterable $clearers = [])
|
||||
{
|
||||
$this->clearers = $clearers;
|
||||
}
|
||||
|
||||
public function clear(string $cacheDir): void
|
||||
{
|
||||
foreach ($this->clearers as $clearer) {
|
||||
$clearer->clear($cacheDir);
|
||||
}
|
||||
}
|
||||
}
|
69
vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php
vendored
Normal file
69
vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
<?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\CacheClearer;
|
||||
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class Psr6CacheClearer implements CacheClearerInterface
|
||||
{
|
||||
private array $pools = [];
|
||||
|
||||
/**
|
||||
* @param array<string, CacheItemPoolInterface> $pools
|
||||
*/
|
||||
public function __construct(array $pools = [])
|
||||
{
|
||||
$this->pools = $pools;
|
||||
}
|
||||
|
||||
public function hasPool(string $name): bool
|
||||
{
|
||||
return isset($this->pools[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException If the cache pool with the given name does not exist
|
||||
*/
|
||||
public function getPool(string $name): CacheItemPoolInterface
|
||||
{
|
||||
if (!$this->hasPool($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('Cache pool not found: "%s".', $name));
|
||||
}
|
||||
|
||||
return $this->pools[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException If the cache pool with the given name does not exist
|
||||
*/
|
||||
public function clearPool(string $name): bool
|
||||
{
|
||||
if (!isset($this->pools[$name])) {
|
||||
throw new \InvalidArgumentException(sprintf('Cache pool not found: "%s".', $name));
|
||||
}
|
||||
|
||||
return $this->pools[$name]->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function clear(string $cacheDir)
|
||||
{
|
||||
foreach ($this->pools as $pool) {
|
||||
$pool->clear();
|
||||
}
|
||||
}
|
||||
}
|
35
vendor/symfony/http-kernel/CacheWarmer/CacheWarmer.php
vendored
Normal file
35
vendor/symfony/http-kernel/CacheWarmer/CacheWarmer.php
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
<?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\CacheWarmer;
|
||||
|
||||
/**
|
||||
* Abstract cache warmer that knows how to write a file to the cache.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
abstract class CacheWarmer implements CacheWarmerInterface
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function writeCacheFile(string $file, $content)
|
||||
{
|
||||
$tmpFile = @tempnam(\dirname($file), basename($file));
|
||||
if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $file)) {
|
||||
@chmod($file, 0666 & ~umask());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw new \RuntimeException(sprintf('Failed to write cache file "%s".', $file));
|
||||
}
|
||||
}
|
141
vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php
vendored
Normal file
141
vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php
vendored
Normal file
@ -0,0 +1,141 @@
|
||||
<?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\CacheWarmer;
|
||||
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* Aggregates several cache warmers into a single one.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class CacheWarmerAggregate implements CacheWarmerInterface
|
||||
{
|
||||
private iterable $warmers;
|
||||
private bool $debug;
|
||||
private ?string $deprecationLogsFilepath;
|
||||
private bool $optionalsEnabled = false;
|
||||
private bool $onlyOptionalsEnabled = false;
|
||||
|
||||
/**
|
||||
* @param iterable<mixed, CacheWarmerInterface> $warmers
|
||||
*/
|
||||
public function __construct(iterable $warmers = [], bool $debug = false, ?string $deprecationLogsFilepath = null)
|
||||
{
|
||||
$this->warmers = $warmers;
|
||||
$this->debug = $debug;
|
||||
$this->deprecationLogsFilepath = $deprecationLogsFilepath;
|
||||
}
|
||||
|
||||
public function enableOptionalWarmers(): void
|
||||
{
|
||||
$this->optionalsEnabled = true;
|
||||
}
|
||||
|
||||
public function enableOnlyOptionalWarmers(): void
|
||||
{
|
||||
$this->onlyOptionalsEnabled = $this->optionalsEnabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $buildDir
|
||||
*/
|
||||
public function warmUp(string $cacheDir, string|SymfonyStyle|null $buildDir = null, ?SymfonyStyle $io = null): array
|
||||
{
|
||||
if ($buildDir instanceof SymfonyStyle) {
|
||||
trigger_deprecation('symfony/http-kernel', '6.4', 'Passing a "%s" as second argument of "%s()" is deprecated, pass it as third argument instead, after the build directory.', SymfonyStyle::class, __METHOD__);
|
||||
$io = $buildDir;
|
||||
$buildDir = null;
|
||||
}
|
||||
|
||||
if ($collectDeprecations = $this->debug && !\defined('PHPUNIT_COMPOSER_INSTALL')) {
|
||||
$collectedLogs = [];
|
||||
$previousHandler = set_error_handler(function ($type, $message, $file, $line) use (&$collectedLogs, &$previousHandler) {
|
||||
if (\E_USER_DEPRECATED !== $type && \E_DEPRECATED !== $type) {
|
||||
return $previousHandler ? $previousHandler($type, $message, $file, $line) : false;
|
||||
}
|
||||
|
||||
if (isset($collectedLogs[$message])) {
|
||||
++$collectedLogs[$message]['count'];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 3);
|
||||
// Clean the trace by removing first frames added by the error handler itself.
|
||||
for ($i = 0; isset($backtrace[$i]); ++$i) {
|
||||
if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) {
|
||||
$backtrace = \array_slice($backtrace, 1 + $i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$collectedLogs[$message] = [
|
||||
'type' => $type,
|
||||
'message' => $message,
|
||||
'file' => $file,
|
||||
'line' => $line,
|
||||
'trace' => $backtrace,
|
||||
'count' => 1,
|
||||
];
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
$preload = [];
|
||||
try {
|
||||
foreach ($this->warmers as $warmer) {
|
||||
if (!$this->optionalsEnabled && $warmer->isOptional()) {
|
||||
continue;
|
||||
}
|
||||
if ($this->onlyOptionalsEnabled && !$warmer->isOptional()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$start = microtime(true);
|
||||
foreach ((array) $warmer->warmUp($cacheDir, $buildDir) as $item) {
|
||||
if (is_dir($item) || (str_starts_with($item, \dirname($cacheDir)) && !is_file($item)) || ($buildDir && str_starts_with($item, \dirname($buildDir)) && !is_file($item))) {
|
||||
throw new \LogicException(sprintf('"%s::warmUp()" should return a list of files or classes but "%s" is none of them.', $warmer::class, $item));
|
||||
}
|
||||
$preload[] = $item;
|
||||
}
|
||||
|
||||
if ($io?->isDebug()) {
|
||||
$io->info(sprintf('"%s" completed in %0.2fms.', $warmer::class, 1000 * (microtime(true) - $start)));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if ($collectDeprecations) {
|
||||
restore_error_handler();
|
||||
|
||||
if (is_file($this->deprecationLogsFilepath)) {
|
||||
$previousLogs = unserialize(file_get_contents($this->deprecationLogsFilepath));
|
||||
if (\is_array($previousLogs)) {
|
||||
$collectedLogs = array_merge($previousLogs, $collectedLogs);
|
||||
}
|
||||
}
|
||||
|
||||
file_put_contents($this->deprecationLogsFilepath, serialize(array_values($collectedLogs)));
|
||||
}
|
||||
}
|
||||
|
||||
return array_values(array_unique($preload));
|
||||
}
|
||||
|
||||
public function isOptional(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
32
vendor/symfony/http-kernel/CacheWarmer/CacheWarmerInterface.php
vendored
Normal file
32
vendor/symfony/http-kernel/CacheWarmer/CacheWarmerInterface.php
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<?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\CacheWarmer;
|
||||
|
||||
/**
|
||||
* Interface for classes able to warm up the cache.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface CacheWarmerInterface extends WarmableInterface
|
||||
{
|
||||
/**
|
||||
* Checks whether this warmer is optional or not.
|
||||
*
|
||||
* Optional warmers can be ignored on certain conditions.
|
||||
*
|
||||
* A warmer should return true if the cache can be
|
||||
* generated incrementally and on-demand.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isOptional();
|
||||
}
|
30
vendor/symfony/http-kernel/CacheWarmer/WarmableInterface.php
vendored
Normal file
30
vendor/symfony/http-kernel/CacheWarmer/WarmableInterface.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\CacheWarmer;
|
||||
|
||||
/**
|
||||
* Interface for classes that support warming their cache.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface WarmableInterface
|
||||
{
|
||||
/**
|
||||
* Warms up the cache.
|
||||
*
|
||||
* @param string $cacheDir Where warm-up artifacts should be stored
|
||||
* @param string|null $buildDir Where read-only artifacts should go; null when called after compile-time
|
||||
*
|
||||
* @return string[] A list of classes or files to preload on PHP 7.4+
|
||||
*/
|
||||
public function warmUp(string $cacheDir /* , string $buildDir = null */);
|
||||
}
|
43
vendor/symfony/http-kernel/Config/FileLocator.php
vendored
Normal file
43
vendor/symfony/http-kernel/Config/FileLocator.php
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Config;
|
||||
|
||||
use Symfony\Component\Config\FileLocator as BaseFileLocator;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
/**
|
||||
* FileLocator uses the KernelInterface to locate resources in bundles.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class FileLocator extends BaseFileLocator
|
||||
{
|
||||
private KernelInterface $kernel;
|
||||
|
||||
public function __construct(KernelInterface $kernel)
|
||||
{
|
||||
$this->kernel = $kernel;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function locate(string $file, ?string $currentPath = null, bool $first = true): string|array
|
||||
{
|
||||
if (isset($file[0]) && '@' === $file[0]) {
|
||||
$resource = $this->kernel->locateResource($file);
|
||||
|
||||
return $first ? $resource : [$resource];
|
||||
}
|
||||
|
||||
return parent::locate($file, $currentPath, $first);
|
||||
}
|
||||
}
|
146
vendor/symfony/http-kernel/Controller/ArgumentResolver.php
vendored
Normal file
146
vendor/symfony/http-kernel/Controller/ArgumentResolver.php
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Attribute\ValueResolver;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestAttributeValueResolver;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestValueResolver;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\SessionValueResolver;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\VariadicValueResolver;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactoryInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\ResolverNotFoundException;
|
||||
use Symfony\Contracts\Service\ServiceProviderInterface;
|
||||
|
||||
/**
|
||||
* Responsible for resolving the arguments passed to an action.
|
||||
*
|
||||
* @author Iltar van der Berg <kjarli@gmail.com>
|
||||
*/
|
||||
final class ArgumentResolver implements ArgumentResolverInterface
|
||||
{
|
||||
private ArgumentMetadataFactoryInterface $argumentMetadataFactory;
|
||||
private iterable $argumentValueResolvers;
|
||||
private ?ContainerInterface $namedResolvers;
|
||||
|
||||
/**
|
||||
* @param iterable<mixed, ArgumentValueResolverInterface|ValueResolverInterface> $argumentValueResolvers
|
||||
*/
|
||||
public function __construct(?ArgumentMetadataFactoryInterface $argumentMetadataFactory = null, iterable $argumentValueResolvers = [], ?ContainerInterface $namedResolvers = null)
|
||||
{
|
||||
$this->argumentMetadataFactory = $argumentMetadataFactory ?? new ArgumentMetadataFactory();
|
||||
$this->argumentValueResolvers = $argumentValueResolvers ?: self::getDefaultArgumentValueResolvers();
|
||||
$this->namedResolvers = $namedResolvers;
|
||||
}
|
||||
|
||||
public function getArguments(Request $request, callable $controller, ?\ReflectionFunctionAbstract $reflector = null): array
|
||||
{
|
||||
$arguments = [];
|
||||
|
||||
foreach ($this->argumentMetadataFactory->createArgumentMetadata($controller, $reflector) as $metadata) {
|
||||
$argumentValueResolvers = $this->argumentValueResolvers;
|
||||
$disabledResolvers = [];
|
||||
|
||||
if ($this->namedResolvers && $attributes = $metadata->getAttributesOfType(ValueResolver::class, $metadata::IS_INSTANCEOF)) {
|
||||
$resolverName = null;
|
||||
foreach ($attributes as $attribute) {
|
||||
if ($attribute->disabled) {
|
||||
$disabledResolvers[$attribute->resolver] = true;
|
||||
} elseif ($resolverName) {
|
||||
throw new \LogicException(sprintf('You can only pin one resolver per argument, but argument "$%s" of "%s()" has more.', $metadata->getName(), $this->getPrettyName($controller)));
|
||||
} else {
|
||||
$resolverName = $attribute->resolver;
|
||||
}
|
||||
}
|
||||
|
||||
if ($resolverName) {
|
||||
if (!$this->namedResolvers->has($resolverName)) {
|
||||
throw new ResolverNotFoundException($resolverName, $this->namedResolvers instanceof ServiceProviderInterface ? array_keys($this->namedResolvers->getProvidedServices()) : []);
|
||||
}
|
||||
|
||||
$argumentValueResolvers = [
|
||||
$this->namedResolvers->get($resolverName),
|
||||
new RequestAttributeValueResolver(),
|
||||
new DefaultValueResolver(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($argumentValueResolvers as $name => $resolver) {
|
||||
if ((!$resolver instanceof ValueResolverInterface || $resolver instanceof TraceableValueResolver) && !$resolver->supports($request, $metadata)) {
|
||||
continue;
|
||||
}
|
||||
if (isset($disabledResolvers[\is_int($name) ? $resolver::class : $name])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
foreach ($resolver->resolve($request, $metadata) as $argument) {
|
||||
++$count;
|
||||
$arguments[] = $argument;
|
||||
}
|
||||
|
||||
if (1 < $count && !$metadata->isVariadic()) {
|
||||
throw new \InvalidArgumentException(sprintf('"%s::resolve()" must yield at most one value for non-variadic arguments.', get_debug_type($resolver)));
|
||||
}
|
||||
|
||||
if ($count) {
|
||||
// continue to the next controller argument
|
||||
continue 2;
|
||||
}
|
||||
|
||||
if (!$resolver instanceof ValueResolverInterface) {
|
||||
throw new \InvalidArgumentException(sprintf('"%s::resolve()" must yield at least one value.', get_debug_type($resolver)));
|
||||
}
|
||||
}
|
||||
|
||||
throw new \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument. Either the argument is nullable and no null value has been provided, no default value has been provided or there is a non-optional argument after this one.', $this->getPrettyName($controller), $metadata->getName()));
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return iterable<int, ArgumentValueResolverInterface>
|
||||
*/
|
||||
public static function getDefaultArgumentValueResolvers(): iterable
|
||||
{
|
||||
return [
|
||||
new RequestAttributeValueResolver(),
|
||||
new RequestValueResolver(),
|
||||
new SessionValueResolver(),
|
||||
new DefaultValueResolver(),
|
||||
new VariadicValueResolver(),
|
||||
];
|
||||
}
|
||||
|
||||
private function getPrettyName($controller): string
|
||||
{
|
||||
if (\is_array($controller)) {
|
||||
if (\is_object($controller[0])) {
|
||||
$controller[0] = get_debug_type($controller[0]);
|
||||
}
|
||||
|
||||
return $controller[0].'::'.$controller[1];
|
||||
}
|
||||
|
||||
if (\is_object($controller)) {
|
||||
return get_debug_type($controller);
|
||||
}
|
||||
|
||||
return $controller;
|
||||
}
|
||||
}
|
93
vendor/symfony/http-kernel/Controller/ArgumentResolver/BackedEnumValueResolver.php
vendored
Normal file
93
vendor/symfony/http-kernel/Controller/ArgumentResolver/BackedEnumValueResolver.php
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* Attempt to resolve backed enum cases from request attributes, for a route path parameter,
|
||||
* leading to a 404 Not Found if the attribute value isn't a valid backing value for the enum type.
|
||||
*
|
||||
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
|
||||
*
|
||||
* @final since Symfony 6.2
|
||||
*/
|
||||
class BackedEnumValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
|
||||
{
|
||||
/**
|
||||
* @deprecated since Symfony 6.2, use resolve() instead
|
||||
*/
|
||||
public function supports(Request $request, ArgumentMetadata $argument): bool
|
||||
{
|
||||
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
|
||||
|
||||
if (!is_subclass_of($argument->getType(), \BackedEnum::class)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($argument->isVariadic()) {
|
||||
// only target route path parameters, which cannot be variadic.
|
||||
return false;
|
||||
}
|
||||
|
||||
// do not support if no value can be resolved at all
|
||||
// letting the \Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver be used
|
||||
// or \Symfony\Component\HttpKernel\Controller\ArgumentResolver fail with a meaningful error.
|
||||
return $request->attributes->has($argument->getName());
|
||||
}
|
||||
|
||||
public function resolve(Request $request, ArgumentMetadata $argument): iterable
|
||||
{
|
||||
if (!is_subclass_of($argument->getType(), \BackedEnum::class)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($argument->isVariadic()) {
|
||||
// only target route path parameters, which cannot be variadic.
|
||||
return [];
|
||||
}
|
||||
|
||||
// do not support if no value can be resolved at all
|
||||
// letting the \Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver be used
|
||||
// or \Symfony\Component\HttpKernel\Controller\ArgumentResolver fail with a meaningful error.
|
||||
if (!$request->attributes->has($argument->getName())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$value = $request->attributes->get($argument->getName());
|
||||
|
||||
if (null === $value) {
|
||||
return [null];
|
||||
}
|
||||
|
||||
if ($value instanceof \BackedEnum) {
|
||||
return [$value];
|
||||
}
|
||||
|
||||
if (!\is_int($value) && !\is_string($value)) {
|
||||
throw new \LogicException(sprintf('Could not resolve the "%s $%s" controller argument: expecting an int or string, got "%s".', $argument->getType(), $argument->getName(), get_debug_type($value)));
|
||||
}
|
||||
|
||||
/** @var class-string<\BackedEnum> $enumType */
|
||||
$enumType = $argument->getType();
|
||||
|
||||
try {
|
||||
return [$enumType::from($value)];
|
||||
} catch (\ValueError|\TypeError $e) {
|
||||
throw new NotFoundHttpException(sprintf('Could not resolve the "%s $%s" controller argument: ', $argument->getType(), $argument->getName()).$e->getMessage(), $e);
|
||||
}
|
||||
}
|
||||
}
|
98
vendor/symfony/http-kernel/Controller/ArgumentResolver/DateTimeValueResolver.php
vendored
Normal file
98
vendor/symfony/http-kernel/Controller/ArgumentResolver/DateTimeValueResolver.php
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
|
||||
|
||||
use Psr\Clock\ClockInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Attribute\MapDateTime;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* Convert DateTime instances from request attribute variable.
|
||||
*
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Tim Goudriaan <tim@codedmonkey.com>
|
||||
*/
|
||||
final class DateTimeValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ?ClockInterface $clock = null,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since Symfony 6.2, use resolve() instead
|
||||
*/
|
||||
public function supports(Request $request, ArgumentMetadata $argument): bool
|
||||
{
|
||||
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
|
||||
|
||||
return is_a($argument->getType(), \DateTimeInterface::class, true) && $request->attributes->has($argument->getName());
|
||||
}
|
||||
|
||||
public function resolve(Request $request, ArgumentMetadata $argument): array
|
||||
{
|
||||
if (!is_a($argument->getType(), \DateTimeInterface::class, true) || !$request->attributes->has($argument->getName())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$value = $request->attributes->get($argument->getName());
|
||||
$class = \DateTimeInterface::class === $argument->getType() ? \DateTimeImmutable::class : $argument->getType();
|
||||
|
||||
if (!$value) {
|
||||
if ($argument->isNullable()) {
|
||||
return [null];
|
||||
}
|
||||
if (!$this->clock) {
|
||||
return [new $class()];
|
||||
}
|
||||
$value = $this->clock->now();
|
||||
}
|
||||
|
||||
if ($value instanceof \DateTimeInterface) {
|
||||
return [$value instanceof $class ? $value : $class::createFromInterface($value)];
|
||||
}
|
||||
|
||||
$format = null;
|
||||
|
||||
if ($attributes = $argument->getAttributes(MapDateTime::class, ArgumentMetadata::IS_INSTANCEOF)) {
|
||||
$attribute = $attributes[0];
|
||||
$format = $attribute->format;
|
||||
}
|
||||
|
||||
if (null !== $format) {
|
||||
$date = $class::createFromFormat($format, $value, $this->clock?->now()->getTimeZone());
|
||||
|
||||
if (($class::getLastErrors() ?: ['warning_count' => 0])['warning_count']) {
|
||||
$date = false;
|
||||
}
|
||||
} else {
|
||||
if (false !== filter_var($value, \FILTER_VALIDATE_INT, ['options' => ['min_range' => 0]])) {
|
||||
$value = '@'.$value;
|
||||
}
|
||||
try {
|
||||
$date = new $class($value, $this->clock?->now()->getTimeZone());
|
||||
} catch (\Exception) {
|
||||
$date = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$date) {
|
||||
throw new NotFoundHttpException(sprintf('Invalid date given for parameter "%s".', $argument->getName()));
|
||||
}
|
||||
|
||||
return [$date];
|
||||
}
|
||||
}
|
48
vendor/symfony/http-kernel/Controller/ArgumentResolver/DefaultValueResolver.php
vendored
Normal file
48
vendor/symfony/http-kernel/Controller/ArgumentResolver/DefaultValueResolver.php
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
|
||||
/**
|
||||
* Yields the default value defined in the action signature when no value has been given.
|
||||
*
|
||||
* @author Iltar van der Berg <kjarli@gmail.com>
|
||||
*/
|
||||
final class DefaultValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
|
||||
{
|
||||
/**
|
||||
* @deprecated since Symfony 6.2, use resolve() instead
|
||||
*/
|
||||
public function supports(Request $request, ArgumentMetadata $argument): bool
|
||||
{
|
||||
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
|
||||
|
||||
return $argument->hasDefaultValue() || (null !== $argument->getType() && $argument->isNullable() && !$argument->isVariadic());
|
||||
}
|
||||
|
||||
public function resolve(Request $request, ArgumentMetadata $argument): array
|
||||
{
|
||||
if ($argument->hasDefaultValue()) {
|
||||
return [$argument->getDefaultValue()];
|
||||
}
|
||||
|
||||
if (null !== $argument->getType() && $argument->isNullable() && !$argument->isVariadic()) {
|
||||
return [null];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
90
vendor/symfony/http-kernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php
vendored
Normal file
90
vendor/symfony/http-kernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
|
||||
/**
|
||||
* Provides an intuitive error message when controller fails because it is not registered as a service.
|
||||
*
|
||||
* @author Simeon Kolev <simeon.kolev9@gmail.com>
|
||||
*/
|
||||
final class NotTaggedControllerValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
|
||||
{
|
||||
private ContainerInterface $container;
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since Symfony 6.2, use resolve() instead
|
||||
*/
|
||||
public function supports(Request $request, ArgumentMetadata $argument): bool
|
||||
{
|
||||
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
|
||||
|
||||
$controller = $request->attributes->get('_controller');
|
||||
|
||||
if (\is_array($controller) && \is_callable($controller, true) && \is_string($controller[0])) {
|
||||
$controller = $controller[0].'::'.$controller[1];
|
||||
} elseif (!\is_string($controller) || '' === $controller) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ('\\' === $controller[0]) {
|
||||
$controller = ltrim($controller, '\\');
|
||||
}
|
||||
|
||||
if (!$this->container->has($controller) && false !== $i = strrpos($controller, ':')) {
|
||||
$controller = substr($controller, 0, $i).strtolower(substr($controller, $i));
|
||||
}
|
||||
|
||||
return false === $this->container->has($controller);
|
||||
}
|
||||
|
||||
public function resolve(Request $request, ArgumentMetadata $argument): array
|
||||
{
|
||||
$controller = $request->attributes->get('_controller');
|
||||
|
||||
if (\is_array($controller) && \is_callable($controller, true) && \is_string($controller[0])) {
|
||||
$controller = $controller[0].'::'.$controller[1];
|
||||
} elseif (!\is_string($controller) || '' === $controller) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ('\\' === $controller[0]) {
|
||||
$controller = ltrim($controller, '\\');
|
||||
}
|
||||
|
||||
if (!$this->container->has($controller)) {
|
||||
$controller = (false !== $i = strrpos($controller, ':'))
|
||||
? substr($controller, 0, $i).strtolower(substr($controller, $i))
|
||||
: $controller.'::__invoke';
|
||||
}
|
||||
|
||||
if ($this->container->has($controller)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$what = sprintf('argument $%s of "%s()"', $argument->getName(), $controller);
|
||||
$message = sprintf('Could not resolve %s, maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"?', $what);
|
||||
|
||||
throw new RuntimeException($message);
|
||||
}
|
||||
}
|
125
vendor/symfony/http-kernel/Controller/ArgumentResolver/QueryParameterValueResolver.php
vendored
Normal file
125
vendor/symfony/http-kernel/Controller/ArgumentResolver/QueryParameterValueResolver.php
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Attribute\MapQueryParameter;
|
||||
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* Resolve arguments of type: array, string, int, float, bool, \BackedEnum from query parameters.
|
||||
*
|
||||
* @author Ruud Kamphuis <ruud@ticketswap.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
* @author Mateusz Anders <anders_mateusz@outlook.com>
|
||||
*/
|
||||
final class QueryParameterValueResolver implements ValueResolverInterface
|
||||
{
|
||||
public function resolve(Request $request, ArgumentMetadata $argument): array
|
||||
{
|
||||
if (!$attribute = $argument->getAttributesOfType(MapQueryParameter::class)[0] ?? null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$name = $attribute->name ?? $argument->getName();
|
||||
if (!$request->query->has($name)) {
|
||||
if ($argument->isNullable() || $argument->hasDefaultValue()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
throw new NotFoundHttpException(sprintf('Missing query parameter "%s".', $name));
|
||||
}
|
||||
|
||||
$value = $request->query->all()[$name];
|
||||
$type = $argument->getType();
|
||||
|
||||
if (null === $attribute->filter && 'array' === $type) {
|
||||
if (!$argument->isVariadic()) {
|
||||
return [(array) $value];
|
||||
}
|
||||
|
||||
$filtered = array_values(array_filter((array) $value, \is_array(...)));
|
||||
|
||||
if ($filtered !== $value && !($attribute->flags & \FILTER_NULL_ON_FAILURE)) {
|
||||
throw new NotFoundHttpException(sprintf('Invalid query parameter "%s".', $name));
|
||||
}
|
||||
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
$options = [
|
||||
'flags' => $attribute->flags | \FILTER_NULL_ON_FAILURE,
|
||||
'options' => $attribute->options,
|
||||
];
|
||||
|
||||
if ('array' === $type || $argument->isVariadic()) {
|
||||
$value = (array) $value;
|
||||
$options['flags'] |= \FILTER_REQUIRE_ARRAY;
|
||||
} else {
|
||||
$options['flags'] |= \FILTER_REQUIRE_SCALAR;
|
||||
}
|
||||
|
||||
$enumType = null;
|
||||
$filter = match ($type) {
|
||||
'array' => \FILTER_DEFAULT,
|
||||
'string' => \FILTER_DEFAULT,
|
||||
'int' => \FILTER_VALIDATE_INT,
|
||||
'float' => \FILTER_VALIDATE_FLOAT,
|
||||
'bool' => \FILTER_VALIDATE_BOOL,
|
||||
default => match ($enumType = is_subclass_of($type, \BackedEnum::class) ? (new \ReflectionEnum($type))->getBackingType()->getName() : null) {
|
||||
'int' => \FILTER_VALIDATE_INT,
|
||||
'string' => \FILTER_DEFAULT,
|
||||
default => throw new \LogicException(sprintf('#[MapQueryParameter] cannot be used on controller argument "%s$%s" of type "%s"; one of array, string, int, float, bool or \BackedEnum should be used.', $argument->isVariadic() ? '...' : '', $argument->getName(), $type ?? 'mixed')),
|
||||
}
|
||||
};
|
||||
|
||||
$value = filter_var($value, $attribute->filter ?? $filter, $options);
|
||||
|
||||
if (null !== $enumType && null !== $value) {
|
||||
$enumFrom = static function ($value) use ($type) {
|
||||
if (!\is_string($value) && !\is_int($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return $type::from($value);
|
||||
} catch (\ValueError) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
$value = \is_array($value) ? array_map($enumFrom, $value) : $enumFrom($value);
|
||||
}
|
||||
|
||||
if (null === $value && !($attribute->flags & \FILTER_NULL_ON_FAILURE)) {
|
||||
throw new NotFoundHttpException(sprintf('Invalid query parameter "%s".', $name));
|
||||
}
|
||||
|
||||
if (!\is_array($value)) {
|
||||
return [$value];
|
||||
}
|
||||
|
||||
$filtered = array_filter($value, static fn ($v) => null !== $v);
|
||||
|
||||
if ($argument->isVariadic()) {
|
||||
$filtered = array_values($filtered);
|
||||
}
|
||||
|
||||
if ($filtered !== $value && !($attribute->flags & \FILTER_NULL_ON_FAILURE)) {
|
||||
throw new NotFoundHttpException(sprintf('Invalid query parameter "%s".', $name));
|
||||
}
|
||||
|
||||
return $argument->isVariadic() ? $filtered : [$filtered];
|
||||
}
|
||||
}
|
40
vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestAttributeValueResolver.php
vendored
Normal file
40
vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestAttributeValueResolver.php
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
|
||||
/**
|
||||
* Yields a non-variadic argument's value from the request attributes.
|
||||
*
|
||||
* @author Iltar van der Berg <kjarli@gmail.com>
|
||||
*/
|
||||
final class RequestAttributeValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
|
||||
{
|
||||
/**
|
||||
* @deprecated since Symfony 6.2, use resolve() instead
|
||||
*/
|
||||
public function supports(Request $request, ArgumentMetadata $argument): bool
|
||||
{
|
||||
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
|
||||
|
||||
return !$argument->isVariadic() && $request->attributes->has($argument->getName());
|
||||
}
|
||||
|
||||
public function resolve(Request $request, ArgumentMetadata $argument): array
|
||||
{
|
||||
return !$argument->isVariadic() && $request->attributes->has($argument->getName()) ? [$request->attributes->get($argument->getName())] : [];
|
||||
}
|
||||
}
|
201
vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php
vendored
Normal file
201
vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Attribute\MapQueryString;
|
||||
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
|
||||
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Component\Serializer\Exception\NotEncodableValueException;
|
||||
use Symfony\Component\Serializer\Exception\PartialDenormalizationException;
|
||||
use Symfony\Component\Serializer\Exception\UnsupportedFormatException;
|
||||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Component\Validator\ConstraintViolation;
|
||||
use Symfony\Component\Validator\ConstraintViolationList;
|
||||
use Symfony\Component\Validator\Exception\ValidationFailedException;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class RequestPayloadValueResolver implements ValueResolverInterface, EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @see \Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer::DISABLE_TYPE_ENFORCEMENT
|
||||
* @see DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS
|
||||
*/
|
||||
private const CONTEXT_DENORMALIZE = [
|
||||
'disable_type_enforcement' => true,
|
||||
'collect_denormalization_errors' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* @see DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS
|
||||
*/
|
||||
private const CONTEXT_DESERIALIZE = [
|
||||
'collect_denormalization_errors' => true,
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
private readonly SerializerInterface&DenormalizerInterface $serializer,
|
||||
private readonly ?ValidatorInterface $validator = null,
|
||||
private readonly ?TranslatorInterface $translator = null,
|
||||
) {
|
||||
}
|
||||
|
||||
public function resolve(Request $request, ArgumentMetadata $argument): iterable
|
||||
{
|
||||
$attribute = $argument->getAttributesOfType(MapQueryString::class, ArgumentMetadata::IS_INSTANCEOF)[0]
|
||||
?? $argument->getAttributesOfType(MapRequestPayload::class, ArgumentMetadata::IS_INSTANCEOF)[0]
|
||||
?? null;
|
||||
|
||||
if (!$attribute) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($argument->isVariadic()) {
|
||||
throw new \LogicException(sprintf('Mapping variadic argument "$%s" is not supported.', $argument->getName()));
|
||||
}
|
||||
|
||||
$attribute->metadata = $argument;
|
||||
|
||||
return [$attribute];
|
||||
}
|
||||
|
||||
public function onKernelControllerArguments(ControllerArgumentsEvent $event): void
|
||||
{
|
||||
$arguments = $event->getArguments();
|
||||
|
||||
foreach ($arguments as $i => $argument) {
|
||||
if ($argument instanceof MapQueryString) {
|
||||
$payloadMapper = 'mapQueryString';
|
||||
$validationFailedCode = $argument->validationFailedStatusCode;
|
||||
} elseif ($argument instanceof MapRequestPayload) {
|
||||
$payloadMapper = 'mapRequestPayload';
|
||||
$validationFailedCode = $argument->validationFailedStatusCode;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
$request = $event->getRequest();
|
||||
|
||||
if (!$type = $argument->metadata->getType()) {
|
||||
throw new \LogicException(sprintf('Could not resolve the "$%s" controller argument: argument should be typed.', $argument->metadata->getName()));
|
||||
}
|
||||
|
||||
if ($this->validator) {
|
||||
$violations = new ConstraintViolationList();
|
||||
try {
|
||||
$payload = $this->$payloadMapper($request, $type, $argument);
|
||||
} catch (PartialDenormalizationException $e) {
|
||||
$trans = $this->translator ? $this->translator->trans(...) : fn ($m, $p) => strtr($m, $p);
|
||||
foreach ($e->getErrors() as $error) {
|
||||
$parameters = [];
|
||||
$template = 'This value was of an unexpected type.';
|
||||
if ($expectedTypes = $error->getExpectedTypes()) {
|
||||
$template = 'This value should be of type {{ type }}.';
|
||||
$parameters['{{ type }}'] = implode('|', $expectedTypes);
|
||||
}
|
||||
if ($error->canUseMessageForUser()) {
|
||||
$parameters['hint'] = $error->getMessage();
|
||||
}
|
||||
$message = $trans($template, $parameters, 'validators');
|
||||
$violations->add(new ConstraintViolation($message, $template, $parameters, null, $error->getPath(), null));
|
||||
}
|
||||
$payload = $e->getData();
|
||||
}
|
||||
|
||||
if (null !== $payload && !\count($violations)) {
|
||||
$violations->addAll($this->validator->validate($payload, null, $argument->validationGroups ?? null));
|
||||
}
|
||||
|
||||
if (\count($violations)) {
|
||||
throw new HttpException($validationFailedCode, implode("\n", array_map(static fn ($e) => $e->getMessage(), iterator_to_array($violations))), new ValidationFailedException($payload, $violations));
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
$payload = $this->$payloadMapper($request, $type, $argument);
|
||||
} catch (PartialDenormalizationException $e) {
|
||||
throw new HttpException($validationFailedCode, implode("\n", array_map(static fn ($e) => $e->getMessage(), $e->getErrors())), $e);
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $payload) {
|
||||
$payload = match (true) {
|
||||
$argument->metadata->hasDefaultValue() => $argument->metadata->getDefaultValue(),
|
||||
$argument->metadata->isNullable() => null,
|
||||
default => throw new HttpException($validationFailedCode)
|
||||
};
|
||||
}
|
||||
|
||||
$arguments[$i] = $payload;
|
||||
}
|
||||
|
||||
$event->setArguments($arguments);
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
KernelEvents::CONTROLLER_ARGUMENTS => 'onKernelControllerArguments',
|
||||
];
|
||||
}
|
||||
|
||||
private function mapQueryString(Request $request, string $type, MapQueryString $attribute): ?object
|
||||
{
|
||||
if (!$data = $request->query->all()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->serializer->denormalize($data, $type, null, $attribute->serializationContext + self::CONTEXT_DENORMALIZE);
|
||||
}
|
||||
|
||||
private function mapRequestPayload(Request $request, string $type, MapRequestPayload $attribute): ?object
|
||||
{
|
||||
if (null === $format = $request->getContentTypeFormat()) {
|
||||
throw new HttpException(Response::HTTP_UNSUPPORTED_MEDIA_TYPE, 'Unsupported format.');
|
||||
}
|
||||
|
||||
if ($attribute->acceptFormat && !\in_array($format, (array) $attribute->acceptFormat, true)) {
|
||||
throw new HttpException(Response::HTTP_UNSUPPORTED_MEDIA_TYPE, sprintf('Unsupported format, expects "%s", but "%s" given.', implode('", "', (array) $attribute->acceptFormat), $format));
|
||||
}
|
||||
|
||||
if ($data = $request->request->all()) {
|
||||
return $this->serializer->denormalize($data, $type, null, $attribute->serializationContext + self::CONTEXT_DENORMALIZE);
|
||||
}
|
||||
|
||||
if ('' === $data = $request->getContent()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ('form' === $format) {
|
||||
throw new HttpException(Response::HTTP_BAD_REQUEST, 'Request payload contains invalid "form" data.');
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->serializer->deserialize($data, $type, $format, self::CONTEXT_DESERIALIZE + $attribute->serializationContext);
|
||||
} catch (UnsupportedFormatException $e) {
|
||||
throw new HttpException(Response::HTTP_UNSUPPORTED_MEDIA_TYPE, sprintf('Unsupported format: "%s".', $format), $e);
|
||||
} catch (NotEncodableValueException $e) {
|
||||
throw new HttpException(Response::HTTP_BAD_REQUEST, sprintf('Request payload contains invalid "%s" data.', $format), $e);
|
||||
}
|
||||
}
|
||||
}
|
40
vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestValueResolver.php
vendored
Normal file
40
vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestValueResolver.php
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
|
||||
/**
|
||||
* Yields the same instance as the request object passed along.
|
||||
*
|
||||
* @author Iltar van der Berg <kjarli@gmail.com>
|
||||
*/
|
||||
final class RequestValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
|
||||
{
|
||||
/**
|
||||
* @deprecated since Symfony 6.2, use resolve() instead
|
||||
*/
|
||||
public function supports(Request $request, ArgumentMetadata $argument): bool
|
||||
{
|
||||
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
|
||||
|
||||
return Request::class === $argument->getType() || is_subclass_of($argument->getType(), Request::class);
|
||||
}
|
||||
|
||||
public function resolve(Request $request, ArgumentMetadata $argument): array
|
||||
{
|
||||
return Request::class === $argument->getType() || is_subclass_of($argument->getType(), Request::class) ? [$request] : [];
|
||||
}
|
||||
}
|
99
vendor/symfony/http-kernel/Controller/ArgumentResolver/ServiceValueResolver.php
vendored
Normal file
99
vendor/symfony/http-kernel/Controller/ArgumentResolver/ServiceValueResolver.php
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
|
||||
/**
|
||||
* Yields a service keyed by _controller and argument name.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
final class ServiceValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
|
||||
{
|
||||
private ContainerInterface $container;
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since Symfony 6.2, use resolve() instead
|
||||
*/
|
||||
public function supports(Request $request, ArgumentMetadata $argument): bool
|
||||
{
|
||||
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
|
||||
|
||||
$controller = $request->attributes->get('_controller');
|
||||
|
||||
if (\is_array($controller) && \is_callable($controller, true) && \is_string($controller[0])) {
|
||||
$controller = $controller[0].'::'.$controller[1];
|
||||
} elseif (!\is_string($controller) || '' === $controller) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ('\\' === $controller[0]) {
|
||||
$controller = ltrim($controller, '\\');
|
||||
}
|
||||
|
||||
if (!$this->container->has($controller) && false !== $i = strrpos($controller, ':')) {
|
||||
$controller = substr($controller, 0, $i).strtolower(substr($controller, $i));
|
||||
}
|
||||
|
||||
return $this->container->has($controller) && $this->container->get($controller)->has($argument->getName());
|
||||
}
|
||||
|
||||
public function resolve(Request $request, ArgumentMetadata $argument): array
|
||||
{
|
||||
$controller = $request->attributes->get('_controller');
|
||||
|
||||
if (\is_array($controller) && \is_callable($controller, true) && \is_string($controller[0])) {
|
||||
$controller = $controller[0].'::'.$controller[1];
|
||||
} elseif (!\is_string($controller) || '' === $controller) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ('\\' === $controller[0]) {
|
||||
$controller = ltrim($controller, '\\');
|
||||
}
|
||||
|
||||
if (!$this->container->has($controller) && false !== $i = strrpos($controller, ':')) {
|
||||
$controller = substr($controller, 0, $i).strtolower(substr($controller, $i));
|
||||
}
|
||||
|
||||
if (!$this->container->has($controller) || !$this->container->get($controller)->has($argument->getName())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
return [$this->container->get($controller)->get($argument->getName())];
|
||||
} catch (RuntimeException $e) {
|
||||
$what = sprintf('argument $%s of "%s()"', $argument->getName(), $controller);
|
||||
$message = preg_replace('/service "\.service_locator\.[^"]++"/', $what, $e->getMessage());
|
||||
|
||||
if ($e->getMessage() === $message) {
|
||||
$message = sprintf('Cannot resolve %s: %s', $what, $message);
|
||||
}
|
||||
|
||||
$r = new \ReflectionProperty($e, 'message');
|
||||
$r->setValue($e, $message);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
59
vendor/symfony/http-kernel/Controller/ArgumentResolver/SessionValueResolver.php
vendored
Normal file
59
vendor/symfony/http-kernel/Controller/ArgumentResolver/SessionValueResolver.php
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
|
||||
/**
|
||||
* Yields the Session.
|
||||
*
|
||||
* @author Iltar van der Berg <kjarli@gmail.com>
|
||||
*/
|
||||
final class SessionValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
|
||||
{
|
||||
/**
|
||||
* @deprecated since Symfony 6.2, use resolve() instead
|
||||
*/
|
||||
public function supports(Request $request, ArgumentMetadata $argument): bool
|
||||
{
|
||||
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
|
||||
|
||||
if (!$request->hasSession()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$type = $argument->getType();
|
||||
if (SessionInterface::class !== $type && !is_subclass_of($type, SessionInterface::class)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $request->getSession() instanceof $type;
|
||||
}
|
||||
|
||||
public function resolve(Request $request, ArgumentMetadata $argument): array
|
||||
{
|
||||
if (!$request->hasSession()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$type = $argument->getType();
|
||||
if (SessionInterface::class !== $type && !is_subclass_of($type, SessionInterface::class)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $request->getSession() instanceof $type ? [$request->getSession()] : [];
|
||||
}
|
||||
}
|
64
vendor/symfony/http-kernel/Controller/ArgumentResolver/TraceableValueResolver.php
vendored
Normal file
64
vendor/symfony/http-kernel/Controller/ArgumentResolver/TraceableValueResolver.php
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
use Symfony\Component\Stopwatch\Stopwatch;
|
||||
|
||||
/**
|
||||
* Provides timing information via the stopwatch.
|
||||
*
|
||||
* @author Iltar van der Berg <kjarli@gmail.com>
|
||||
*/
|
||||
final class TraceableValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
|
||||
{
|
||||
private ArgumentValueResolverInterface|ValueResolverInterface $inner;
|
||||
private Stopwatch $stopwatch;
|
||||
|
||||
public function __construct(ArgumentValueResolverInterface|ValueResolverInterface $inner, Stopwatch $stopwatch)
|
||||
{
|
||||
$this->inner = $inner;
|
||||
$this->stopwatch = $stopwatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since Symfony 6.2, use resolve() instead
|
||||
*/
|
||||
public function supports(Request $request, ArgumentMetadata $argument): bool
|
||||
{
|
||||
if ($this->inner instanceof ValueResolverInterface) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$method = $this->inner::class.'::'.__FUNCTION__;
|
||||
$this->stopwatch->start($method, 'controller.argument_value_resolver');
|
||||
|
||||
$return = $this->inner->supports($request, $argument);
|
||||
|
||||
$this->stopwatch->stop($method);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
public function resolve(Request $request, ArgumentMetadata $argument): iterable
|
||||
{
|
||||
$method = $this->inner::class.'::'.__FUNCTION__;
|
||||
$this->stopwatch->start($method, 'controller.argument_value_resolver');
|
||||
|
||||
yield from $this->inner->resolve($request, $argument);
|
||||
|
||||
$this->stopwatch->stop($method);
|
||||
}
|
||||
}
|
52
vendor/symfony/http-kernel/Controller/ArgumentResolver/UidValueResolver.php
vendored
Normal file
52
vendor/symfony/http-kernel/Controller/ArgumentResolver/UidValueResolver.php
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\Uid\AbstractUid;
|
||||
|
||||
final class UidValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
|
||||
{
|
||||
/**
|
||||
* @deprecated since Symfony 6.2, use resolve() instead
|
||||
*/
|
||||
public function supports(Request $request, ArgumentMetadata $argument): bool
|
||||
{
|
||||
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
|
||||
|
||||
return !$argument->isVariadic()
|
||||
&& \is_string($request->attributes->get($argument->getName()))
|
||||
&& null !== $argument->getType()
|
||||
&& is_subclass_of($argument->getType(), AbstractUid::class, true);
|
||||
}
|
||||
|
||||
public function resolve(Request $request, ArgumentMetadata $argument): array
|
||||
{
|
||||
if ($argument->isVariadic()
|
||||
|| !\is_string($value = $request->attributes->get($argument->getName()))
|
||||
|| null === ($uidClass = $argument->getType())
|
||||
|| !is_subclass_of($uidClass, AbstractUid::class, true)
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
return [$uidClass::fromString($value)];
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
throw new NotFoundHttpException(sprintf('The uid for the "%s" parameter is invalid.', $argument->getName()), $e);
|
||||
}
|
||||
}
|
||||
}
|
50
vendor/symfony/http-kernel/Controller/ArgumentResolver/VariadicValueResolver.php
vendored
Normal file
50
vendor/symfony/http-kernel/Controller/ArgumentResolver/VariadicValueResolver.php
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
|
||||
/**
|
||||
* Yields a variadic argument's values from the request attributes.
|
||||
*
|
||||
* @author Iltar van der Berg <kjarli@gmail.com>
|
||||
*/
|
||||
final class VariadicValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
|
||||
{
|
||||
/**
|
||||
* @deprecated since Symfony 6.2, use resolve() instead
|
||||
*/
|
||||
public function supports(Request $request, ArgumentMetadata $argument): bool
|
||||
{
|
||||
@trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__);
|
||||
|
||||
return $argument->isVariadic() && $request->attributes->has($argument->getName());
|
||||
}
|
||||
|
||||
public function resolve(Request $request, ArgumentMetadata $argument): array
|
||||
{
|
||||
if (!$argument->isVariadic() || !$request->attributes->has($argument->getName())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$values = $request->attributes->get($argument->getName());
|
||||
|
||||
if (!\is_array($values)) {
|
||||
throw new \InvalidArgumentException(sprintf('The action argument "...$%1$s" is required to be an array, the request attribute "%1$s" contains a type of "%2$s" instead.', $argument->getName(), get_debug_type($values)));
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
}
|
32
vendor/symfony/http-kernel/Controller/ArgumentResolverInterface.php
vendored
Normal file
32
vendor/symfony/http-kernel/Controller/ArgumentResolverInterface.php
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* An ArgumentResolverInterface instance knows how to determine the
|
||||
* arguments for a specific action.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface ArgumentResolverInterface
|
||||
{
|
||||
/**
|
||||
* Returns the arguments to pass to the controller.
|
||||
*
|
||||
* @param \ReflectionFunctionAbstract|null $reflector
|
||||
*
|
||||
* @throws \RuntimeException When no value could be provided for a required argument
|
||||
*/
|
||||
public function getArguments(Request $request, callable $controller/* , \ReflectionFunctionAbstract $reflector = null */): array;
|
||||
}
|
35
vendor/symfony/http-kernel/Controller/ArgumentValueResolverInterface.php
vendored
Normal file
35
vendor/symfony/http-kernel/Controller/ArgumentValueResolverInterface.php
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
|
||||
/**
|
||||
* Responsible for resolving the value of an argument based on its metadata.
|
||||
*
|
||||
* @author Iltar van der Berg <kjarli@gmail.com>
|
||||
*
|
||||
* @deprecated since Symfony 6.2, implement ValueResolverInterface instead
|
||||
*/
|
||||
interface ArgumentValueResolverInterface
|
||||
{
|
||||
/**
|
||||
* Whether this resolver can resolve the value for the given ArgumentMetadata.
|
||||
*/
|
||||
public function supports(Request $request, ArgumentMetadata $argument): bool;
|
||||
|
||||
/**
|
||||
* Returns the possible value(s).
|
||||
*/
|
||||
public function resolve(Request $request, ArgumentMetadata $argument): iterable;
|
||||
}
|
63
vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php
vendored
Normal file
63
vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
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.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
|
||||
*/
|
||||
class ContainerControllerResolver extends ControllerResolver
|
||||
{
|
||||
protected $container;
|
||||
|
||||
public function __construct(ContainerInterface $container, ?LoggerInterface $logger = null)
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
parent::__construct($logger);
|
||||
}
|
||||
|
||||
protected function instantiateController(string $class): object
|
||||
{
|
||||
$class = ltrim($class, '\\');
|
||||
|
||||
if ($this->container->has($class)) {
|
||||
return $this->container->get($class);
|
||||
}
|
||||
|
||||
try {
|
||||
return parent::instantiateController($class);
|
||||
} catch (\Error $e) {
|
||||
}
|
||||
|
||||
$this->throwExceptionIfControllerWasRemoved($class, $e);
|
||||
|
||||
if ($e instanceof \ArgumentCountError) {
|
||||
throw new \InvalidArgumentException(sprintf('Controller "%s" has required constructor arguments and does not exist in the container. Did you forget to define the controller as a service?', $class), 0, $e);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf('Controller "%s" does neither exist as service nor as class.', $class), 0, $e);
|
||||
}
|
||||
|
||||
private function throwExceptionIfControllerWasRemoved(string $controller, \Throwable $previous): void
|
||||
{
|
||||
if ($this->container instanceof Container && isset($this->container->getRemovedIds()[$controller])) {
|
||||
throw new \InvalidArgumentException(sprintf('Controller "%s" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"?', $controller), 0, $previous);
|
||||
}
|
||||
}
|
||||
}
|
44
vendor/symfony/http-kernel/Controller/ControllerReference.php
vendored
Normal file
44
vendor/symfony/http-kernel/Controller/ControllerReference.php
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller;
|
||||
|
||||
use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface;
|
||||
|
||||
/**
|
||||
* Acts as a marker and a data holder for a Controller.
|
||||
*
|
||||
* Some methods in Symfony accept both a URI (as a string) or a controller as
|
||||
* an argument. In the latter case, instead of passing an array representing
|
||||
* the controller, you can use an instance of this class.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @see FragmentRendererInterface
|
||||
*/
|
||||
class ControllerReference
|
||||
{
|
||||
public $controller;
|
||||
public $attributes = [];
|
||||
public $query = [];
|
||||
|
||||
/**
|
||||
* @param string $controller The controller name
|
||||
* @param array $attributes An array of parameters to add to the Request attributes
|
||||
* @param array $query An array of parameters to add to the Request query string
|
||||
*/
|
||||
public function __construct(string $controller, array $attributes = [], array $query = [])
|
||||
{
|
||||
$this->controller = $controller;
|
||||
$this->attributes = $attributes;
|
||||
$this->query = $query;
|
||||
}
|
||||
}
|
279
vendor/symfony/http-kernel/Controller/ControllerResolver.php
vendored
Normal file
279
vendor/symfony/http-kernel/Controller/ControllerResolver.php
vendored
Normal file
@ -0,0 +1,279 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Attribute\AsController;
|
||||
|
||||
/**
|
||||
* This implementation uses the '_controller' request attribute to determine
|
||||
* the controller to execute.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Tobias Schultze <http://tobion.de>
|
||||
*/
|
||||
class ControllerResolver implements ControllerResolverInterface
|
||||
{
|
||||
private ?LoggerInterface $logger;
|
||||
private array $allowedControllerTypes = [];
|
||||
private array $allowedControllerAttributes = [AsController::class => AsController::class];
|
||||
|
||||
public function __construct(?LoggerInterface $logger = null)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<class-string> $types
|
||||
* @param array<class-string> $attributes
|
||||
*/
|
||||
public function allowControllers(array $types = [], array $attributes = []): void
|
||||
{
|
||||
foreach ($types as $type) {
|
||||
$this->allowedControllerTypes[$type] = $type;
|
||||
}
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
$this->allowedControllerAttributes[$attribute] = $attribute;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequestException when the request has attribute "_check_controller_is_allowed" set to true and the controller is not allowed
|
||||
*/
|
||||
public function getController(Request $request): callable|false
|
||||
{
|
||||
if (!$controller = $request->attributes->get('_controller')) {
|
||||
$this->logger?->warning('Unable to look for the controller as the "_controller" parameter is missing.');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (\is_array($controller)) {
|
||||
if (isset($controller[0]) && \is_string($controller[0]) && isset($controller[1])) {
|
||||
try {
|
||||
$controller[0] = $this->instantiateController($controller[0]);
|
||||
} catch (\Error|\LogicException $e) {
|
||||
if (\is_callable($controller)) {
|
||||
return $this->checkController($request, $controller);
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
if (!\is_callable($controller)) {
|
||||
throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$this->getControllerError($controller));
|
||||
}
|
||||
|
||||
return $this->checkController($request, $controller);
|
||||
}
|
||||
|
||||
if (\is_object($controller)) {
|
||||
if (!\is_callable($controller)) {
|
||||
throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$this->getControllerError($controller));
|
||||
}
|
||||
|
||||
return $this->checkController($request, $controller);
|
||||
}
|
||||
|
||||
if (\function_exists($controller)) {
|
||||
return $this->checkController($request, $controller);
|
||||
}
|
||||
|
||||
try {
|
||||
$callable = $this->createController($controller);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$e->getMessage(), 0, $e);
|
||||
}
|
||||
|
||||
if (!\is_callable($callable)) {
|
||||
throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$this->getControllerError($callable));
|
||||
}
|
||||
|
||||
return $this->checkController($request, $callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a callable for the given controller.
|
||||
*
|
||||
* @throws \InvalidArgumentException When the controller cannot be created
|
||||
*/
|
||||
protected function createController(string $controller): callable
|
||||
{
|
||||
if (!str_contains($controller, '::')) {
|
||||
$controller = $this->instantiateController($controller);
|
||||
|
||||
if (!\is_callable($controller)) {
|
||||
throw new \InvalidArgumentException($this->getControllerError($controller));
|
||||
}
|
||||
|
||||
return $controller;
|
||||
}
|
||||
|
||||
[$class, $method] = explode('::', $controller, 2);
|
||||
|
||||
try {
|
||||
$controller = [$this->instantiateController($class), $method];
|
||||
} catch (\Error|\LogicException $e) {
|
||||
try {
|
||||
if ((new \ReflectionMethod($class, $method))->isStatic()) {
|
||||
return $class.'::'.$method;
|
||||
}
|
||||
} catch (\ReflectionException) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if (!\is_callable($controller)) {
|
||||
throw new \InvalidArgumentException($this->getControllerError($controller));
|
||||
}
|
||||
|
||||
return $controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instantiated controller.
|
||||
*/
|
||||
protected function instantiateController(string $class): object
|
||||
{
|
||||
return new $class();
|
||||
}
|
||||
|
||||
private function getControllerError(mixed $callable): string
|
||||
{
|
||||
if (\is_string($callable)) {
|
||||
if (str_contains($callable, '::')) {
|
||||
$callable = explode('::', $callable, 2);
|
||||
} else {
|
||||
return sprintf('Function "%s" does not exist.', $callable);
|
||||
}
|
||||
}
|
||||
|
||||
if (\is_object($callable)) {
|
||||
$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_debug_type($callable), $alternativeMsg);
|
||||
}
|
||||
|
||||
if (!\is_array($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)) {
|
||||
return 'Invalid array callable, expected [controller, method].';
|
||||
}
|
||||
|
||||
[$controller, $method] = $callable;
|
||||
|
||||
if (\is_string($controller) && !class_exists($controller)) {
|
||||
return sprintf('Class "%s" does not exist.', $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);
|
||||
}
|
||||
|
||||
$collection = $this->getClassMethodsWithoutMagicMethods($controller);
|
||||
|
||||
$alternatives = [];
|
||||
|
||||
foreach ($collection as $item) {
|
||||
$lev = levenshtein($method, $item);
|
||||
|
||||
if ($lev <= \strlen($method) / 3 || str_contains($item, $method)) {
|
||||
$alternatives[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
asort($alternatives);
|
||||
|
||||
$message = sprintf('Expected method "%s" on class "%s"', $method, $className);
|
||||
|
||||
if (\count($alternatives) > 0) {
|
||||
$message .= sprintf(', did you mean "%s"?', implode('", "', $alternatives));
|
||||
} else {
|
||||
$message .= sprintf('. Available methods: "%s".', implode('", "', $collection));
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
private function getClassMethodsWithoutMagicMethods($classOrObject): array
|
||||
{
|
||||
$methods = get_class_methods($classOrObject);
|
||||
|
||||
return array_filter($methods, fn (string $method) => 0 !== strncmp($method, '__', 2));
|
||||
}
|
||||
|
||||
private function checkController(Request $request, callable $controller): callable
|
||||
{
|
||||
if (!$request->attributes->get('_check_controller_is_allowed', false)) {
|
||||
return $controller;
|
||||
}
|
||||
|
||||
$r = null;
|
||||
|
||||
if (\is_array($controller)) {
|
||||
[$class, $name] = $controller;
|
||||
$name = (\is_string($class) ? $class : $class::class).'::'.$name;
|
||||
} elseif (\is_object($controller) && !$controller instanceof \Closure) {
|
||||
$class = $controller;
|
||||
$name = $class::class.'::__invoke';
|
||||
} else {
|
||||
$r = new \ReflectionFunction($controller);
|
||||
$name = $r->name;
|
||||
|
||||
if (str_contains($name, '{closure}')) {
|
||||
$name = $class = \Closure::class;
|
||||
} elseif ($class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) {
|
||||
$class = $class->name;
|
||||
$name = $class.'::'.$name;
|
||||
}
|
||||
}
|
||||
|
||||
if ($class) {
|
||||
foreach ($this->allowedControllerTypes as $type) {
|
||||
if (is_a($class, $type, true)) {
|
||||
return $controller;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$r ??= new \ReflectionClass($class);
|
||||
|
||||
foreach ($r->getAttributes() as $attribute) {
|
||||
if (isset($this->allowedControllerAttributes[$attribute->getName()])) {
|
||||
return $controller;
|
||||
}
|
||||
}
|
||||
|
||||
if (str_contains($name, '@anonymous')) {
|
||||
$name = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $name);
|
||||
}
|
||||
|
||||
if (-1 === $request->attributes->get('_check_controller_is_allowed')) {
|
||||
trigger_deprecation('symfony/http-kernel', '6.4', 'Callable "%s()" is not allowed as a controller. Did you miss tagging it with "#[AsController]" or registering its type with "%s::allowControllers()"?', $name, self::class);
|
||||
|
||||
return $controller;
|
||||
}
|
||||
|
||||
throw new BadRequestException(sprintf('Callable "%s()" is not allowed as a controller. Did you miss tagging it with "#[AsController]" or registering its type with "%s::allowControllers()"?', $name, self::class));
|
||||
}
|
||||
}
|
41
vendor/symfony/http-kernel/Controller/ControllerResolverInterface.php
vendored
Normal file
41
vendor/symfony/http-kernel/Controller/ControllerResolverInterface.php
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* A ControllerResolverInterface implementation knows how to determine the
|
||||
* controller to execute based on a Request object.
|
||||
*
|
||||
* A Controller can be any valid PHP callable.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface ControllerResolverInterface
|
||||
{
|
||||
/**
|
||||
* Returns the Controller instance associated with a Request.
|
||||
*
|
||||
* As several resolvers can exist for a single application, a resolver must
|
||||
* return false when it is not able to determine the controller.
|
||||
*
|
||||
* The resolver must only throw an exception when it should be able to load a
|
||||
* controller but cannot because of some errors made by the developer.
|
||||
*
|
||||
* @return callable|false A PHP callable representing the Controller,
|
||||
* or false if this resolver is not able to determine the controller
|
||||
*
|
||||
* @throws \LogicException If a controller was found based on the request but it is not callable
|
||||
*/
|
||||
public function getController(Request $request): callable|false;
|
||||
}
|
62
vendor/symfony/http-kernel/Controller/ErrorController.php
vendored
Normal file
62
vendor/symfony/http-kernel/Controller/ErrorController.php
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller;
|
||||
|
||||
use Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRendererInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
|
||||
/**
|
||||
* Renders error or exception pages from a given FlattenException.
|
||||
*
|
||||
* @author Yonel Ceruto <yonelceruto@gmail.com>
|
||||
* @author Matthias Pigulla <mp@webfactory.de>
|
||||
*/
|
||||
class ErrorController
|
||||
{
|
||||
private HttpKernelInterface $kernel;
|
||||
private string|object|array|null $controller;
|
||||
private ErrorRendererInterface $errorRenderer;
|
||||
|
||||
public function __construct(HttpKernelInterface $kernel, string|object|array|null $controller, ErrorRendererInterface $errorRenderer)
|
||||
{
|
||||
$this->kernel = $kernel;
|
||||
$this->controller = $controller;
|
||||
$this->errorRenderer = $errorRenderer;
|
||||
}
|
||||
|
||||
public function __invoke(\Throwable $exception): Response
|
||||
{
|
||||
$exception = $this->errorRenderer->render($exception);
|
||||
|
||||
return new Response($exception->getAsString(), $exception->getStatusCode(), $exception->getHeaders());
|
||||
}
|
||||
|
||||
public function preview(Request $request, int $code): Response
|
||||
{
|
||||
/*
|
||||
* This Request mimics the parameters set by
|
||||
* \Symfony\Component\HttpKernel\EventListener\ErrorListener::duplicateRequest, with
|
||||
* the additional "showException" flag.
|
||||
*/
|
||||
$subRequest = $request->duplicate(null, null, [
|
||||
'_controller' => $this->controller,
|
||||
'exception' => new HttpException($code, 'This is a sample exception.'),
|
||||
'logger' => null,
|
||||
'showException' => false,
|
||||
]);
|
||||
|
||||
return $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
|
||||
}
|
||||
}
|
45
vendor/symfony/http-kernel/Controller/TraceableArgumentResolver.php
vendored
Normal file
45
vendor/symfony/http-kernel/Controller/TraceableArgumentResolver.php
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Stopwatch\Stopwatch;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class TraceableArgumentResolver implements ArgumentResolverInterface
|
||||
{
|
||||
private ArgumentResolverInterface $resolver;
|
||||
private Stopwatch $stopwatch;
|
||||
|
||||
public function __construct(ArgumentResolverInterface $resolver, Stopwatch $stopwatch)
|
||||
{
|
||||
$this->resolver = $resolver;
|
||||
$this->stopwatch = $stopwatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \ReflectionFunctionAbstract|null $reflector
|
||||
*/
|
||||
public function getArguments(Request $request, callable $controller/* , \ReflectionFunctionAbstract $reflector = null */): array
|
||||
{
|
||||
$reflector = 2 < \func_num_args() ? func_get_arg(2) : null;
|
||||
$e = $this->stopwatch->start('controller.get_arguments');
|
||||
|
||||
try {
|
||||
return $this->resolver->getArguments($request, $controller, $reflector);
|
||||
} finally {
|
||||
$e->stop();
|
||||
}
|
||||
}
|
||||
}
|
41
vendor/symfony/http-kernel/Controller/TraceableControllerResolver.php
vendored
Normal file
41
vendor/symfony/http-kernel/Controller/TraceableControllerResolver.php
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Stopwatch\Stopwatch;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class TraceableControllerResolver implements ControllerResolverInterface
|
||||
{
|
||||
private ControllerResolverInterface $resolver;
|
||||
private Stopwatch $stopwatch;
|
||||
|
||||
public function __construct(ControllerResolverInterface $resolver, Stopwatch $stopwatch)
|
||||
{
|
||||
$this->resolver = $resolver;
|
||||
$this->stopwatch = $stopwatch;
|
||||
}
|
||||
|
||||
public function getController(Request $request): callable|false
|
||||
{
|
||||
$e = $this->stopwatch->start('controller.get_callable');
|
||||
|
||||
try {
|
||||
return $this->resolver->getController($request);
|
||||
} finally {
|
||||
$e->stop();
|
||||
}
|
||||
}
|
||||
}
|
28
vendor/symfony/http-kernel/Controller/ValueResolverInterface.php
vendored
Normal file
28
vendor/symfony/http-kernel/Controller/ValueResolverInterface.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Controller;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
|
||||
/**
|
||||
* Responsible for resolving the value of an argument based on its metadata.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
interface ValueResolverInterface
|
||||
{
|
||||
/**
|
||||
* Returns the possible value(s).
|
||||
*/
|
||||
public function resolve(Request $request, ArgumentMetadata $argument): iterable;
|
||||
}
|
145
vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadata.php
vendored
Normal file
145
vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadata.php
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\ControllerMetadata;
|
||||
|
||||
/**
|
||||
* Responsible for storing metadata of an argument.
|
||||
*
|
||||
* @author Iltar van der Berg <kjarli@gmail.com>
|
||||
*/
|
||||
class ArgumentMetadata
|
||||
{
|
||||
public const IS_INSTANCEOF = 2;
|
||||
|
||||
private string $name;
|
||||
private ?string $type;
|
||||
private bool $isVariadic;
|
||||
private bool $hasDefaultValue;
|
||||
private mixed $defaultValue;
|
||||
private bool $isNullable;
|
||||
private array $attributes;
|
||||
|
||||
/**
|
||||
* @param object[] $attributes
|
||||
*/
|
||||
public function __construct(string $name, ?string $type, bool $isVariadic, bool $hasDefaultValue, mixed $defaultValue, bool $isNullable = false, array $attributes = [])
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->type = $type;
|
||||
$this->isVariadic = $isVariadic;
|
||||
$this->hasDefaultValue = $hasDefaultValue;
|
||||
$this->defaultValue = $defaultValue;
|
||||
$this->isNullable = $isNullable || null === $type || ($hasDefaultValue && null === $defaultValue);
|
||||
$this->attributes = $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name as given in PHP, $foo would yield "foo".
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the argument.
|
||||
*
|
||||
* The type is the PHP class in 5.5+ and additionally the basic type in PHP 7.0+.
|
||||
*/
|
||||
public function getType(): ?string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the argument is defined as "...$variadic".
|
||||
*/
|
||||
public function isVariadic(): bool
|
||||
{
|
||||
return $this->isVariadic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the argument has a default value.
|
||||
*
|
||||
* Implies whether an argument is optional.
|
||||
*/
|
||||
public function hasDefaultValue(): bool
|
||||
{
|
||||
return $this->hasDefaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the argument accepts null values.
|
||||
*/
|
||||
public function isNullable(): bool
|
||||
{
|
||||
return $this->isNullable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default value of the argument.
|
||||
*
|
||||
* @throws \LogicException if no default value is present; {@see self::hasDefaultValue()}
|
||||
*/
|
||||
public function getDefaultValue(): mixed
|
||||
{
|
||||
if (!$this->hasDefaultValue) {
|
||||
throw new \LogicException(sprintf('Argument $%s does not have a default value. Use "%s::hasDefaultValue()" to avoid this exception.', $this->name, __CLASS__));
|
||||
}
|
||||
|
||||
return $this->defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string $name
|
||||
* @param self::IS_INSTANCEOF|0 $flags
|
||||
*
|
||||
* @return array<object>
|
||||
*/
|
||||
public function getAttributes(?string $name = null, int $flags = 0): array
|
||||
{
|
||||
if (!$name) {
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
return $this->getAttributesOfType($name, $flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T of object
|
||||
*
|
||||
* @param class-string<T> $name
|
||||
* @param self::IS_INSTANCEOF|0 $flags
|
||||
*
|
||||
* @return array<T>
|
||||
*/
|
||||
public function getAttributesOfType(string $name, int $flags = 0): array
|
||||
{
|
||||
$attributes = [];
|
||||
if ($flags & self::IS_INSTANCEOF) {
|
||||
foreach ($this->attributes as $attribute) {
|
||||
if ($attribute instanceof $name) {
|
||||
$attributes[] = $attribute;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($this->attributes as $attribute) {
|
||||
if ($attribute::class === $name) {
|
||||
$attributes[] = $attribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
}
|
56
vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php
vendored
Normal file
56
vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
<?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\ControllerMetadata;
|
||||
|
||||
/**
|
||||
* Builds {@see ArgumentMetadata} objects based on the given Controller.
|
||||
*
|
||||
* @author Iltar van der Berg <kjarli@gmail.com>
|
||||
*/
|
||||
final class ArgumentMetadataFactory implements ArgumentMetadataFactoryInterface
|
||||
{
|
||||
public function createArgumentMetadata(string|object|array $controller, ?\ReflectionFunctionAbstract $reflector = null): array
|
||||
{
|
||||
$arguments = [];
|
||||
$reflector ??= new \ReflectionFunction($controller(...));
|
||||
|
||||
foreach ($reflector->getParameters() as $param) {
|
||||
$attributes = [];
|
||||
foreach ($param->getAttributes() as $reflectionAttribute) {
|
||||
if (class_exists($reflectionAttribute->getName())) {
|
||||
$attributes[] = $reflectionAttribute->newInstance();
|
||||
}
|
||||
}
|
||||
|
||||
$arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param), $param->isVariadic(), $param->isDefaultValueAvailable(), $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, $param->allowsNull(), $attributes);
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an associated type to the given parameter if available.
|
||||
*/
|
||||
private function getType(\ReflectionParameter $parameter): ?string
|
||||
{
|
||||
if (!$type = $parameter->getType()) {
|
||||
return null;
|
||||
}
|
||||
$name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type;
|
||||
|
||||
return match (strtolower($name)) {
|
||||
'self' => $parameter->getDeclaringClass()?->name,
|
||||
'parent' => get_parent_class($parameter->getDeclaringClass()?->name ?? '') ?: null,
|
||||
default => $name,
|
||||
};
|
||||
}
|
||||
}
|
27
vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactoryInterface.php
vendored
Normal file
27
vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactoryInterface.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\ControllerMetadata;
|
||||
|
||||
/**
|
||||
* Builds method argument data.
|
||||
*
|
||||
* @author Iltar van der Berg <kjarli@gmail.com>
|
||||
*/
|
||||
interface ArgumentMetadataFactoryInterface
|
||||
{
|
||||
/**
|
||||
* @param \ReflectionFunctionAbstract|null $reflector
|
||||
*
|
||||
* @return ArgumentMetadata[]
|
||||
*/
|
||||
public function createArgumentMetadata(string|object|array $controller/* , \ReflectionFunctionAbstract $reflector = null */): array;
|
||||
}
|
38
vendor/symfony/http-kernel/DataCollector/AjaxDataCollector.php
vendored
Normal file
38
vendor/symfony/http-kernel/DataCollector/AjaxDataCollector.php
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* @author Bart van den Burg <bart@burgov.nl>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class AjaxDataCollector extends DataCollector
|
||||
{
|
||||
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
|
||||
{
|
||||
// all collecting is done client side
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
// all collecting is done client side
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'ajax';
|
||||
}
|
||||
}
|
259
vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php
vendored
Normal file
259
vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php
vendored
Normal file
@ -0,0 +1,259 @@
|
||||
<?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\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Kernel;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use Symfony\Component\VarDumper\Caster\ClassStub;
|
||||
use Symfony\Component\VarDumper\Cloner\Data;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class ConfigDataCollector extends DataCollector implements LateDataCollectorInterface
|
||||
{
|
||||
private KernelInterface $kernel;
|
||||
|
||||
/**
|
||||
* Sets the Kernel associated with this Request.
|
||||
*/
|
||||
public function setKernel(?KernelInterface $kernel = null): void
|
||||
{
|
||||
if (1 > \func_num_args()) {
|
||||
trigger_deprecation('symfony/http-kernel', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
|
||||
}
|
||||
|
||||
$this->kernel = $kernel;
|
||||
}
|
||||
|
||||
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
|
||||
{
|
||||
$eom = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE);
|
||||
$eol = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE);
|
||||
|
||||
$this->data = [
|
||||
'token' => $response->headers->get('X-Debug-Token'),
|
||||
'symfony_version' => Kernel::VERSION,
|
||||
'symfony_minor_version' => sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION),
|
||||
'symfony_lts' => 4 === Kernel::MINOR_VERSION,
|
||||
'symfony_state' => $this->determineSymfonyState(),
|
||||
'symfony_eom' => $eom->format('F Y'),
|
||||
'symfony_eol' => $eol->format('F Y'),
|
||||
'env' => isset($this->kernel) ? $this->kernel->getEnvironment() : 'n/a',
|
||||
'debug' => isset($this->kernel) ? $this->kernel->isDebug() : 'n/a',
|
||||
'php_version' => \PHP_VERSION,
|
||||
'php_architecture' => \PHP_INT_SIZE * 8,
|
||||
'php_intl_locale' => class_exists(\Locale::class, false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a',
|
||||
'php_timezone' => date_default_timezone_get(),
|
||||
'xdebug_enabled' => \extension_loaded('xdebug'),
|
||||
'apcu_enabled' => \extension_loaded('apcu') && filter_var(\ini_get('apc.enabled'), \FILTER_VALIDATE_BOOL),
|
||||
'zend_opcache_enabled' => \extension_loaded('Zend OPcache') && filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOL),
|
||||
'bundles' => [],
|
||||
'sapi_name' => \PHP_SAPI,
|
||||
];
|
||||
|
||||
if (isset($this->kernel)) {
|
||||
foreach ($this->kernel->getBundles() as $name => $bundle) {
|
||||
$this->data['bundles'][$name] = new ClassStub($bundle::class);
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match('~^(\d+(?:\.\d+)*)(.+)?$~', $this->data['php_version'], $matches) && isset($matches[2])) {
|
||||
$this->data['php_version'] = $matches[1];
|
||||
$this->data['php_version_extra'] = $matches[2];
|
||||
}
|
||||
}
|
||||
|
||||
public function lateCollect(): void
|
||||
{
|
||||
$this->data = $this->cloneVar($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the token.
|
||||
*/
|
||||
public function getToken(): ?string
|
||||
{
|
||||
return $this->data['token'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Symfony version.
|
||||
*/
|
||||
public function getSymfonyVersion(): string
|
||||
{
|
||||
return $this->data['symfony_version'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the state of the current Symfony release
|
||||
* as one of: unknown, dev, stable, eom, eol.
|
||||
*/
|
||||
public function getSymfonyState(): string
|
||||
{
|
||||
return $this->data['symfony_state'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minor Symfony version used (without patch numbers of extra
|
||||
* suffix like "RC", "beta", etc.).
|
||||
*/
|
||||
public function getSymfonyMinorVersion(): string
|
||||
{
|
||||
return $this->data['symfony_minor_version'];
|
||||
}
|
||||
|
||||
public function isSymfonyLts(): bool
|
||||
{
|
||||
return $this->data['symfony_lts'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the human readable date when this Symfony version ends its
|
||||
* maintenance period.
|
||||
*/
|
||||
public function getSymfonyEom(): string
|
||||
{
|
||||
return $this->data['symfony_eom'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the human readable date when this Symfony version reaches its
|
||||
* "end of life" and won't receive bugs or security fixes.
|
||||
*/
|
||||
public function getSymfonyEol(): string
|
||||
{
|
||||
return $this->data['symfony_eol'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the PHP version.
|
||||
*/
|
||||
public function getPhpVersion(): string
|
||||
{
|
||||
return $this->data['php_version'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the PHP version extra part.
|
||||
*/
|
||||
public function getPhpVersionExtra(): ?string
|
||||
{
|
||||
return $this->data['php_version_extra'] ?? null;
|
||||
}
|
||||
|
||||
public function getPhpArchitecture(): int
|
||||
{
|
||||
return $this->data['php_architecture'];
|
||||
}
|
||||
|
||||
public function getPhpIntlLocale(): string
|
||||
{
|
||||
return $this->data['php_intl_locale'];
|
||||
}
|
||||
|
||||
public function getPhpTimezone(): string
|
||||
{
|
||||
return $this->data['php_timezone'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the environment.
|
||||
*/
|
||||
public function getEnv(): string
|
||||
{
|
||||
return $this->data['env'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the debug is enabled.
|
||||
*
|
||||
* @return bool|string true if debug is enabled, false otherwise or a string if no kernel was set
|
||||
*/
|
||||
public function isDebug(): bool|string
|
||||
{
|
||||
return $this->data['debug'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the Xdebug is enabled.
|
||||
*/
|
||||
public function hasXdebug(): bool
|
||||
{
|
||||
return $this->data['xdebug_enabled'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the function xdebug_info is available.
|
||||
*/
|
||||
public function hasXdebugInfo(): bool
|
||||
{
|
||||
return \function_exists('xdebug_info');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if APCu is enabled.
|
||||
*/
|
||||
public function hasApcu(): bool
|
||||
{
|
||||
return $this->data['apcu_enabled'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if Zend OPcache is enabled.
|
||||
*/
|
||||
public function hasZendOpcache(): bool
|
||||
{
|
||||
return $this->data['zend_opcache_enabled'];
|
||||
}
|
||||
|
||||
public function getBundles(): array|Data
|
||||
{
|
||||
return $this->data['bundles'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the PHP SAPI name.
|
||||
*/
|
||||
public function getSapiName(): string
|
||||
{
|
||||
return $this->data['sapi_name'];
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'config';
|
||||
}
|
||||
|
||||
private function determineSymfonyState(): string
|
||||
{
|
||||
$now = new \DateTimeImmutable();
|
||||
$eom = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE)->modify('last day of this month');
|
||||
$eol = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE)->modify('last day of this month');
|
||||
|
||||
if ($now > $eol) {
|
||||
$versionState = 'eol';
|
||||
} elseif ($now > $eom) {
|
||||
$versionState = 'eom';
|
||||
} elseif ('' !== Kernel::EXTRA_VERSION) {
|
||||
$versionState = 'dev';
|
||||
} else {
|
||||
$versionState = 'stable';
|
||||
}
|
||||
|
||||
return $versionState;
|
||||
}
|
||||
}
|
113
vendor/symfony/http-kernel/DataCollector/DataCollector.php
vendored
Normal file
113
vendor/symfony/http-kernel/DataCollector/DataCollector.php
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
<?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\DataCollector;
|
||||
|
||||
use Symfony\Component\VarDumper\Caster\CutStub;
|
||||
use Symfony\Component\VarDumper\Caster\ReflectionCaster;
|
||||
use Symfony\Component\VarDumper\Cloner\ClonerInterface;
|
||||
use Symfony\Component\VarDumper\Cloner\Data;
|
||||
use Symfony\Component\VarDumper\Cloner\Stub;
|
||||
use Symfony\Component\VarDumper\Cloner\VarCloner;
|
||||
|
||||
/**
|
||||
* DataCollector.
|
||||
*
|
||||
* Children of this class must store the collected data in the data property.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Bernhard Schussek <bschussek@symfony.com>
|
||||
*/
|
||||
abstract class DataCollector implements DataCollectorInterface
|
||||
{
|
||||
/**
|
||||
* @var array|Data
|
||||
*/
|
||||
protected $data = [];
|
||||
|
||||
private ClonerInterface $cloner;
|
||||
|
||||
/**
|
||||
* Converts the variable into a serializable Data instance.
|
||||
*
|
||||
* This array can be displayed in the template using
|
||||
* the VarDumper component.
|
||||
*/
|
||||
protected function cloneVar(mixed $var): Data
|
||||
{
|
||||
if ($var instanceof Data) {
|
||||
return $var;
|
||||
}
|
||||
if (!isset($this->cloner)) {
|
||||
$this->cloner = new VarCloner();
|
||||
$this->cloner->setMaxItems(-1);
|
||||
$this->cloner->addCasters($this->getCasters());
|
||||
}
|
||||
|
||||
return $this->cloner->cloneVar($var);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return callable[] The casters to add to the cloner
|
||||
*/
|
||||
protected function getCasters()
|
||||
{
|
||||
$casters = [
|
||||
'*' => function ($v, array $a, Stub $s, $isNested) {
|
||||
if (!$v instanceof Stub) {
|
||||
foreach ($a as $k => $v) {
|
||||
if (\is_object($v) && !$v instanceof \DateTimeInterface && !$v instanceof Stub) {
|
||||
$a[$k] = new CutStub($v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $a;
|
||||
},
|
||||
] + ReflectionCaster::UNSET_CLOSURE_FILE_INFO;
|
||||
|
||||
return $casters;
|
||||
}
|
||||
|
||||
public function __sleep(): array
|
||||
{
|
||||
return ['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function __wakeup()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal to prevent implementing \Serializable
|
||||
*/
|
||||
final protected function serialize(): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal to prevent implementing \Serializable
|
||||
*/
|
||||
final protected function unserialize(string $data): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->data = [];
|
||||
}
|
||||
}
|
38
vendor/symfony/http-kernel/DataCollector/DataCollectorInterface.php
vendored
Normal file
38
vendor/symfony/http-kernel/DataCollector/DataCollectorInterface.php
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Contracts\Service\ResetInterface;
|
||||
|
||||
/**
|
||||
* DataCollectorInterface.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface DataCollectorInterface extends ResetInterface
|
||||
{
|
||||
/**
|
||||
* Collects data for the given Request and Response.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function collect(Request $request, Response $response, ?\Throwable $exception = null);
|
||||
|
||||
/**
|
||||
* Returns the name of the collector.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName();
|
||||
}
|
287
vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php
vendored
Normal file
287
vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php
vendored
Normal file
@ -0,0 +1,287 @@
|
||||
<?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\DataCollector;
|
||||
|
||||
use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Stopwatch\Stopwatch;
|
||||
use Symfony\Component\VarDumper\Cloner\Data;
|
||||
use Symfony\Component\VarDumper\Cloner\VarCloner;
|
||||
use Symfony\Component\VarDumper\Dumper\CliDumper;
|
||||
use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider;
|
||||
use Symfony\Component\VarDumper\Dumper\DataDumperInterface;
|
||||
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
|
||||
use Symfony\Component\VarDumper\Server\Connection;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class DumpDataCollector extends DataCollector implements DataDumperInterface
|
||||
{
|
||||
private ?Stopwatch $stopwatch = null;
|
||||
private string|FileLinkFormatter|false $fileLinkFormat;
|
||||
private int $dataCount = 0;
|
||||
private bool $isCollected = true;
|
||||
private int $clonesCount = 0;
|
||||
private int $clonesIndex = 0;
|
||||
private array $rootRefs;
|
||||
private string $charset;
|
||||
private ?RequestStack $requestStack;
|
||||
private DataDumperInterface|Connection|null $dumper;
|
||||
private mixed $sourceContextProvider;
|
||||
private bool $webMode;
|
||||
|
||||
public function __construct(?Stopwatch $stopwatch = null, string|FileLinkFormatter|null $fileLinkFormat = null, ?string $charset = null, ?RequestStack $requestStack = null, DataDumperInterface|Connection|null $dumper = null, ?bool $webMode = null)
|
||||
{
|
||||
$fileLinkFormat = $fileLinkFormat ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
|
||||
$this->stopwatch = $stopwatch;
|
||||
$this->fileLinkFormat = $fileLinkFormat instanceof FileLinkFormatter && false === $fileLinkFormat->format('', 0) ? false : $fileLinkFormat;
|
||||
$this->charset = $charset ?: \ini_get('php.output_encoding') ?: \ini_get('default_charset') ?: 'UTF-8';
|
||||
$this->requestStack = $requestStack;
|
||||
$this->dumper = $dumper;
|
||||
$this->webMode = $webMode ?? !\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true);
|
||||
|
||||
// All clones share these properties by reference:
|
||||
$this->rootRefs = [
|
||||
&$this->data,
|
||||
&$this->dataCount,
|
||||
&$this->isCollected,
|
||||
&$this->clonesCount,
|
||||
];
|
||||
|
||||
$this->sourceContextProvider = $dumper instanceof Connection && isset($dumper->getContextProviders()['source']) ? $dumper->getContextProviders()['source'] : new SourceContextProvider($this->charset);
|
||||
}
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
$this->clonesIndex = ++$this->clonesCount;
|
||||
}
|
||||
|
||||
public function dump(Data $data): ?string
|
||||
{
|
||||
$this->stopwatch?->start('dump');
|
||||
|
||||
['name' => $name, 'file' => $file, 'line' => $line, 'file_excerpt' => $fileExcerpt] = $this->sourceContextProvider->getContext();
|
||||
|
||||
if (!$this->dumper || $this->dumper instanceof Connection && !$this->dumper->write($data)) {
|
||||
$this->isCollected = false;
|
||||
}
|
||||
|
||||
$context = $data->getContext();
|
||||
$label = $context['label'] ?? '';
|
||||
unset($context['label']);
|
||||
$data = $data->withContext($context);
|
||||
|
||||
if ($this->dumper && !$this->dumper instanceof Connection) {
|
||||
$this->doDump($this->dumper, $data, $name, $file, $line, $label);
|
||||
}
|
||||
|
||||
if (!$this->dataCount) {
|
||||
$this->data = [];
|
||||
}
|
||||
$this->data[] = compact('data', 'name', 'file', 'line', 'fileExcerpt', 'label');
|
||||
++$this->dataCount;
|
||||
|
||||
$this->stopwatch?->stop('dump');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
|
||||
{
|
||||
if (!$this->dataCount) {
|
||||
$this->data = [];
|
||||
}
|
||||
|
||||
// Sub-requests and programmatic calls stay in the collected profile.
|
||||
if ($this->dumper || ($this->requestStack && $this->requestStack->getMainRequest() !== $request) || $request->isXmlHttpRequest() || $request->headers->has('Origin')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// In all other conditions that remove the web debug toolbar, dumps are written on the output.
|
||||
if (!$this->requestStack
|
||||
|| !$response->headers->has('X-Debug-Token')
|
||||
|| $response->isRedirection()
|
||||
|| ($response->headers->has('Content-Type') && !str_contains($response->headers->get('Content-Type') ?? '', 'html'))
|
||||
|| 'html' !== $request->getRequestFormat()
|
||||
|| false === strripos($response->getContent(), '</body>')
|
||||
) {
|
||||
if ($response->headers->has('Content-Type') && str_contains($response->headers->get('Content-Type') ?? '', 'html')) {
|
||||
$dumper = new HtmlDumper('php://output', $this->charset);
|
||||
$dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
|
||||
} else {
|
||||
$dumper = new CliDumper('php://output', $this->charset);
|
||||
$dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
|
||||
}
|
||||
|
||||
foreach ($this->data as $dump) {
|
||||
$this->doDump($dumper, $dump['data'], $dump['name'], $dump['file'], $dump['line'], $dump['label'] ?? '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
$this->stopwatch?->reset();
|
||||
parent::reset();
|
||||
$this->dataCount = 0;
|
||||
$this->isCollected = true;
|
||||
$this->clonesCount = 0;
|
||||
$this->clonesIndex = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function __sleep(): array
|
||||
{
|
||||
if (!$this->dataCount) {
|
||||
$this->data = [];
|
||||
}
|
||||
|
||||
if ($this->clonesCount !== $this->clonesIndex) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$this->data[] = $this->fileLinkFormat;
|
||||
$this->data[] = $this->charset;
|
||||
$this->dataCount = 0;
|
||||
$this->isCollected = true;
|
||||
|
||||
return parent::__sleep();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function __wakeup(): void
|
||||
{
|
||||
parent::__wakeup();
|
||||
|
||||
$charset = array_pop($this->data);
|
||||
$fileLinkFormat = array_pop($this->data);
|
||||
$this->dataCount = \count($this->data);
|
||||
foreach ($this->data as $dump) {
|
||||
if (!\is_string($dump['name']) || !\is_string($dump['file']) || !\is_int($dump['line'])) {
|
||||
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
|
||||
}
|
||||
}
|
||||
|
||||
self::__construct($this->stopwatch, \is_string($fileLinkFormat) || $fileLinkFormat instanceof FileLinkFormatter ? $fileLinkFormat : null, \is_string($charset) ? $charset : null);
|
||||
}
|
||||
|
||||
public function getDumpsCount(): int
|
||||
{
|
||||
return $this->dataCount;
|
||||
}
|
||||
|
||||
public function getDumps(string $format, int $maxDepthLimit = -1, int $maxItemsPerDepth = -1): array
|
||||
{
|
||||
$data = fopen('php://memory', 'r+');
|
||||
|
||||
if ('html' === $format) {
|
||||
$dumper = new HtmlDumper($data, $this->charset);
|
||||
$dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
|
||||
} else {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid dump format: "%s".', $format));
|
||||
}
|
||||
$dumps = [];
|
||||
|
||||
if (!$this->dataCount) {
|
||||
return $this->data = [];
|
||||
}
|
||||
|
||||
foreach ($this->data as $dump) {
|
||||
$dumper->dump($dump['data']->withMaxDepth($maxDepthLimit)->withMaxItemsPerDepth($maxItemsPerDepth));
|
||||
$dump['data'] = stream_get_contents($data, -1, 0);
|
||||
ftruncate($data, 0);
|
||||
rewind($data);
|
||||
$dumps[] = $dump;
|
||||
}
|
||||
|
||||
return $dumps;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'dump';
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if (0 === $this->clonesCount-- && !$this->isCollected && $this->dataCount) {
|
||||
$this->clonesCount = 0;
|
||||
$this->isCollected = true;
|
||||
|
||||
$h = headers_list();
|
||||
$i = \count($h);
|
||||
array_unshift($h, 'Content-Type: '.\ini_get('default_mimetype'));
|
||||
while (0 !== stripos($h[$i], 'Content-Type:')) {
|
||||
--$i;
|
||||
}
|
||||
|
||||
if ($this->webMode) {
|
||||
$dumper = new HtmlDumper('php://output', $this->charset);
|
||||
$dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
|
||||
} else {
|
||||
$dumper = new CliDumper('php://output', $this->charset);
|
||||
$dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
|
||||
}
|
||||
|
||||
foreach ($this->data as $i => $dump) {
|
||||
$this->data[$i] = null;
|
||||
$this->doDump($dumper, $dump['data'], $dump['name'], $dump['file'], $dump['line'], $dump['label'] ?? '');
|
||||
}
|
||||
|
||||
$this->data = [];
|
||||
$this->dataCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private function doDump(DataDumperInterface $dumper, Data $data, string $name, string $file, int $line, string $label): void
|
||||
{
|
||||
if ($dumper instanceof CliDumper) {
|
||||
$contextDumper = function ($name, $file, $line, $fmt, $label) {
|
||||
$this->line = '' !== $label ? $this->style('meta', $label).' in ' : '';
|
||||
|
||||
if ($this instanceof HtmlDumper) {
|
||||
if ($file) {
|
||||
$s = $this->style('meta', '%s');
|
||||
$f = strip_tags($this->style('', $file));
|
||||
$name = strip_tags($this->style('', $name));
|
||||
if ($fmt && $link = \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : $fmt->format($file, $line)) {
|
||||
$name = sprintf('<a href="%s" title="%s">'.$s.'</a>', strip_tags($this->style('', $link)), $f, $name);
|
||||
} else {
|
||||
$name = sprintf('<abbr title="%s">'.$s.'</abbr>', $f, $name);
|
||||
}
|
||||
} else {
|
||||
$name = $this->style('meta', $name);
|
||||
}
|
||||
$this->line .= $name.' on line '.$this->style('meta', $line).':';
|
||||
} else {
|
||||
$this->line .= $this->style('meta', $name).' on line '.$this->style('meta', $line).':';
|
||||
}
|
||||
$this->dumpLine(0);
|
||||
};
|
||||
$contextDumper = $contextDumper->bindTo($dumper, $dumper);
|
||||
$contextDumper($name, $file, $line, $this->fileLinkFormat, $label);
|
||||
} else {
|
||||
$cloner = new VarCloner();
|
||||
$dumper->dump($cloner->cloneVar(('' !== $label ? $label.' in ' : '').$name.' on line '.$line.':'));
|
||||
}
|
||||
$dumper->dump($data);
|
||||
}
|
||||
}
|
140
vendor/symfony/http-kernel/DataCollector/EventDataCollector.php
vendored
Normal file
140
vendor/symfony/http-kernel/DataCollector/EventDataCollector.php
vendored
Normal file
@ -0,0 +1,140 @@
|
||||
<?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\DataCollector;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\VarDumper\Cloner\Data;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Contracts\Service\ResetInterface;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @see TraceableEventDispatcher
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class EventDataCollector extends DataCollector implements LateDataCollectorInterface
|
||||
{
|
||||
/** @var iterable<EventDispatcherInterface> */
|
||||
private iterable $dispatchers;
|
||||
private ?Request $currentRequest = null;
|
||||
|
||||
/**
|
||||
* @param iterable<EventDispatcherInterface>|EventDispatcherInterface|null $dispatchers
|
||||
*/
|
||||
public function __construct(
|
||||
iterable|EventDispatcherInterface|null $dispatchers = null,
|
||||
private ?RequestStack $requestStack = null,
|
||||
private string $defaultDispatcher = 'event_dispatcher',
|
||||
) {
|
||||
if ($dispatchers instanceof EventDispatcherInterface) {
|
||||
$dispatchers = [$this->defaultDispatcher => $dispatchers];
|
||||
}
|
||||
$this->dispatchers = $dispatchers ?? [];
|
||||
}
|
||||
|
||||
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
|
||||
{
|
||||
$this->currentRequest = $this->requestStack && $this->requestStack->getMainRequest() !== $request ? $request : null;
|
||||
$this->data = [];
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
parent::reset();
|
||||
|
||||
foreach ($this->dispatchers as $dispatcher) {
|
||||
if ($dispatcher instanceof ResetInterface) {
|
||||
$dispatcher->reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function lateCollect(): void
|
||||
{
|
||||
foreach ($this->dispatchers as $name => $dispatcher) {
|
||||
if (!$dispatcher instanceof TraceableEventDispatcher) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->setCalledListeners($dispatcher->getCalledListeners($this->currentRequest), $name);
|
||||
$this->setNotCalledListeners($dispatcher->getNotCalledListeners($this->currentRequest), $name);
|
||||
$this->setOrphanedEvents($dispatcher->getOrphanedEvents($this->currentRequest), $name);
|
||||
}
|
||||
|
||||
$this->data = $this->cloneVar($this->data);
|
||||
}
|
||||
|
||||
public function getData(): array|Data
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TraceableEventDispatcher
|
||||
*/
|
||||
public function setCalledListeners(array $listeners, ?string $dispatcher = null): void
|
||||
{
|
||||
$this->data[$dispatcher ?? $this->defaultDispatcher]['called_listeners'] = $listeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TraceableEventDispatcher
|
||||
*/
|
||||
public function getCalledListeners(?string $dispatcher = null): array|Data
|
||||
{
|
||||
return $this->data[$dispatcher ?? $this->defaultDispatcher]['called_listeners'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TraceableEventDispatcher
|
||||
*/
|
||||
public function setNotCalledListeners(array $listeners, ?string $dispatcher = null): void
|
||||
{
|
||||
$this->data[$dispatcher ?? $this->defaultDispatcher]['not_called_listeners'] = $listeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TraceableEventDispatcher
|
||||
*/
|
||||
public function getNotCalledListeners(?string $dispatcher = null): array|Data
|
||||
{
|
||||
return $this->data[$dispatcher ?? $this->defaultDispatcher]['not_called_listeners'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $events An array of orphaned events
|
||||
*
|
||||
* @see TraceableEventDispatcher
|
||||
*/
|
||||
public function setOrphanedEvents(array $events, ?string $dispatcher = null): void
|
||||
{
|
||||
$this->data[$dispatcher ?? $this->defaultDispatcher]['orphaned_events'] = $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TraceableEventDispatcher
|
||||
*/
|
||||
public function getOrphanedEvents(?string $dispatcher = null): array|Data
|
||||
{
|
||||
return $this->data[$dispatcher ?? $this->defaultDispatcher]['orphaned_events'] ?? [];
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'events';
|
||||
}
|
||||
}
|
68
vendor/symfony/http-kernel/DataCollector/ExceptionDataCollector.php
vendored
Normal file
68
vendor/symfony/http-kernel/DataCollector/ExceptionDataCollector.php
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
<?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\DataCollector;
|
||||
|
||||
use Symfony\Component\ErrorHandler\Exception\FlattenException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class ExceptionDataCollector extends DataCollector
|
||||
{
|
||||
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
|
||||
{
|
||||
if (null !== $exception) {
|
||||
$this->data = [
|
||||
'exception' => FlattenException::createWithDataRepresentation($exception),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
public function hasException(): bool
|
||||
{
|
||||
return isset($this->data['exception']);
|
||||
}
|
||||
|
||||
public function getException(): \Exception|FlattenException
|
||||
{
|
||||
return $this->data['exception'];
|
||||
}
|
||||
|
||||
public function getMessage(): string
|
||||
{
|
||||
return $this->data['exception']->getMessage();
|
||||
}
|
||||
|
||||
public function getCode(): int
|
||||
{
|
||||
return $this->data['exception']->getCode();
|
||||
}
|
||||
|
||||
public function getStatusCode(): int
|
||||
{
|
||||
return $this->data['exception']->getStatusCode();
|
||||
}
|
||||
|
||||
public function getTrace(): array
|
||||
{
|
||||
return $this->data['exception']->getTrace();
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'exception';
|
||||
}
|
||||
}
|
27
vendor/symfony/http-kernel/DataCollector/LateDataCollectorInterface.php
vendored
Normal file
27
vendor/symfony/http-kernel/DataCollector/LateDataCollectorInterface.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DataCollector;
|
||||
|
||||
/**
|
||||
* LateDataCollectorInterface.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface LateDataCollectorInterface
|
||||
{
|
||||
/**
|
||||
* Collects data as late as possible.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function lateCollect();
|
||||
}
|
335
vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php
vendored
Normal file
335
vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php
vendored
Normal file
@ -0,0 +1,335 @@
|
||||
<?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\DataCollector;
|
||||
|
||||
use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Log\DebugLoggerConfigurator;
|
||||
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
|
||||
use Symfony\Component\VarDumper\Cloner\Data;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class LoggerDataCollector extends DataCollector implements LateDataCollectorInterface
|
||||
{
|
||||
private ?DebugLoggerInterface $logger;
|
||||
private ?string $containerPathPrefix;
|
||||
private ?Request $currentRequest = null;
|
||||
private ?RequestStack $requestStack;
|
||||
private ?array $processedLogs = null;
|
||||
|
||||
public function __construct(?object $logger = null, ?string $containerPathPrefix = null, ?RequestStack $requestStack = null)
|
||||
{
|
||||
$this->logger = DebugLoggerConfigurator::getDebugLogger($logger);
|
||||
$this->containerPathPrefix = $containerPathPrefix;
|
||||
$this->requestStack = $requestStack;
|
||||
}
|
||||
|
||||
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
|
||||
{
|
||||
$this->currentRequest = $this->requestStack && $this->requestStack->getMainRequest() !== $request ? $request : null;
|
||||
}
|
||||
|
||||
public function lateCollect(): void
|
||||
{
|
||||
if ($this->logger) {
|
||||
$containerDeprecationLogs = $this->getContainerDeprecationLogs();
|
||||
$this->data = $this->computeErrorsCount($containerDeprecationLogs);
|
||||
// get compiler logs later (only when they are needed) to improve performance
|
||||
$this->data['compiler_logs'] = [];
|
||||
$this->data['compiler_logs_filepath'] = $this->containerPathPrefix.'Compiler.log';
|
||||
$this->data['logs'] = $this->sanitizeLogs(array_merge($this->logger->getLogs($this->currentRequest), $containerDeprecationLogs));
|
||||
$this->data = $this->cloneVar($this->data);
|
||||
}
|
||||
$this->currentRequest = null;
|
||||
}
|
||||
|
||||
public function getLogs(): Data|array
|
||||
{
|
||||
return $this->data['logs'] ?? [];
|
||||
}
|
||||
|
||||
public function getProcessedLogs(): array
|
||||
{
|
||||
if (null !== $this->processedLogs) {
|
||||
return $this->processedLogs;
|
||||
}
|
||||
|
||||
$rawLogs = $this->getLogs();
|
||||
if ([] === $rawLogs) {
|
||||
return $this->processedLogs = $rawLogs;
|
||||
}
|
||||
|
||||
$logs = [];
|
||||
foreach ($this->getLogs()->getValue() as $rawLog) {
|
||||
$rawLogData = $rawLog->getValue();
|
||||
|
||||
if ($rawLogData['priority']->getValue() > 300) {
|
||||
$logType = 'error';
|
||||
} elseif (isset($rawLogData['scream']) && false === $rawLogData['scream']->getValue()) {
|
||||
$logType = 'deprecation';
|
||||
} elseif (isset($rawLogData['scream']) && true === $rawLogData['scream']->getValue()) {
|
||||
$logType = 'silenced';
|
||||
} else {
|
||||
$logType = 'regular';
|
||||
}
|
||||
|
||||
$logs[] = [
|
||||
'type' => $logType,
|
||||
'errorCount' => $rawLog['errorCount'] ?? 1,
|
||||
'timestamp' => $rawLogData['timestamp_rfc3339']->getValue(),
|
||||
'priority' => $rawLogData['priority']->getValue(),
|
||||
'priorityName' => $rawLogData['priorityName']->getValue(),
|
||||
'channel' => $rawLogData['channel']->getValue(),
|
||||
'message' => $rawLogData['message'],
|
||||
'context' => $rawLogData['context'],
|
||||
];
|
||||
}
|
||||
|
||||
// sort logs from oldest to newest
|
||||
usort($logs, static fn ($logA, $logB) => $logA['timestamp'] <=> $logB['timestamp']);
|
||||
|
||||
return $this->processedLogs = $logs;
|
||||
}
|
||||
|
||||
public function getFilters(): array
|
||||
{
|
||||
$filters = [
|
||||
'channel' => [],
|
||||
'priority' => [
|
||||
'Debug' => 100,
|
||||
'Info' => 200,
|
||||
'Notice' => 250,
|
||||
'Warning' => 300,
|
||||
'Error' => 400,
|
||||
'Critical' => 500,
|
||||
'Alert' => 550,
|
||||
'Emergency' => 600,
|
||||
],
|
||||
];
|
||||
|
||||
$allChannels = [];
|
||||
foreach ($this->getProcessedLogs() as $log) {
|
||||
if ('' === trim($log['channel'] ?? '')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$allChannels[] = $log['channel'];
|
||||
}
|
||||
$channels = array_unique($allChannels);
|
||||
sort($channels);
|
||||
$filters['channel'] = $channels;
|
||||
|
||||
return $filters;
|
||||
}
|
||||
|
||||
public function getPriorities(): Data|array
|
||||
{
|
||||
return $this->data['priorities'] ?? [];
|
||||
}
|
||||
|
||||
public function countErrors(): int
|
||||
{
|
||||
return $this->data['error_count'] ?? 0;
|
||||
}
|
||||
|
||||
public function countDeprecations(): int
|
||||
{
|
||||
return $this->data['deprecation_count'] ?? 0;
|
||||
}
|
||||
|
||||
public function countWarnings(): int
|
||||
{
|
||||
return $this->data['warning_count'] ?? 0;
|
||||
}
|
||||
|
||||
public function countScreams(): int
|
||||
{
|
||||
return $this->data['scream_count'] ?? 0;
|
||||
}
|
||||
|
||||
public function getCompilerLogs(): Data
|
||||
{
|
||||
return $this->cloneVar($this->getContainerCompilerLogs($this->data['compiler_logs_filepath'] ?? null));
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'logger';
|
||||
}
|
||||
|
||||
private function getContainerDeprecationLogs(): array
|
||||
{
|
||||
if (null === $this->containerPathPrefix || !is_file($file = $this->containerPathPrefix.'Deprecations.log')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ('' === $logContent = trim(file_get_contents($file))) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$bootTime = filemtime($file);
|
||||
$logs = [];
|
||||
foreach (unserialize($logContent) as $log) {
|
||||
$log['context'] = ['exception' => new SilencedErrorContext($log['type'], $log['file'], $log['line'], $log['trace'], $log['count'])];
|
||||
$log['timestamp'] = $bootTime;
|
||||
$log['timestamp_rfc3339'] = (new \DateTimeImmutable())->setTimestamp($bootTime)->format(\DateTimeInterface::RFC3339_EXTENDED);
|
||||
$log['priority'] = 100;
|
||||
$log['priorityName'] = 'DEBUG';
|
||||
$log['channel'] = null;
|
||||
$log['scream'] = false;
|
||||
unset($log['type'], $log['file'], $log['line'], $log['trace'], $log['trace'], $log['count']);
|
||||
$logs[] = $log;
|
||||
}
|
||||
|
||||
return $logs;
|
||||
}
|
||||
|
||||
private function getContainerCompilerLogs(?string $compilerLogsFilepath = null): array
|
||||
{
|
||||
if (!$compilerLogsFilepath || !is_file($compilerLogsFilepath)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$logs = [];
|
||||
foreach (file($compilerLogsFilepath, \FILE_IGNORE_NEW_LINES) as $log) {
|
||||
$log = explode(': ', $log, 2);
|
||||
if (!isset($log[1]) || !preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)++$/', $log[0])) {
|
||||
$log = ['Unknown Compiler Pass', implode(': ', $log)];
|
||||
}
|
||||
|
||||
$logs[$log[0]][] = ['message' => $log[1]];
|
||||
}
|
||||
|
||||
return $logs;
|
||||
}
|
||||
|
||||
private function sanitizeLogs(array $logs): array
|
||||
{
|
||||
$sanitizedLogs = [];
|
||||
$silencedLogs = [];
|
||||
|
||||
foreach ($logs as $log) {
|
||||
if (!$this->isSilencedOrDeprecationErrorLog($log)) {
|
||||
$sanitizedLogs[] = $log;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$message = '_'.$log['message'];
|
||||
$exception = $log['context']['exception'];
|
||||
|
||||
if ($exception instanceof SilencedErrorContext) {
|
||||
if (isset($silencedLogs[$h = spl_object_hash($exception)])) {
|
||||
continue;
|
||||
}
|
||||
$silencedLogs[$h] = true;
|
||||
|
||||
if (!isset($sanitizedLogs[$message])) {
|
||||
$sanitizedLogs[$message] = $log + [
|
||||
'errorCount' => 0,
|
||||
'scream' => true,
|
||||
];
|
||||
}
|
||||
$sanitizedLogs[$message]['errorCount'] += $exception->count;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$errorId = hash('xxh128', "{$exception->getSeverity()}/{$exception->getLine()}/{$exception->getFile()}\0{$message}", true);
|
||||
|
||||
if (isset($sanitizedLogs[$errorId])) {
|
||||
++$sanitizedLogs[$errorId]['errorCount'];
|
||||
} else {
|
||||
$log += [
|
||||
'errorCount' => 1,
|
||||
'scream' => false,
|
||||
];
|
||||
|
||||
$sanitizedLogs[$errorId] = $log;
|
||||
}
|
||||
}
|
||||
|
||||
return array_values($sanitizedLogs);
|
||||
}
|
||||
|
||||
private function isSilencedOrDeprecationErrorLog(array $log): bool
|
||||
{
|
||||
if (!isset($log['context']['exception'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$exception = $log['context']['exception'];
|
||||
|
||||
if ($exception instanceof SilencedErrorContext) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($exception instanceof \ErrorException && \in_array($exception->getSeverity(), [\E_DEPRECATED, \E_USER_DEPRECATED], true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function computeErrorsCount(array $containerDeprecationLogs): array
|
||||
{
|
||||
$silencedLogs = [];
|
||||
$count = [
|
||||
'error_count' => $this->logger->countErrors($this->currentRequest),
|
||||
'deprecation_count' => 0,
|
||||
'warning_count' => 0,
|
||||
'scream_count' => 0,
|
||||
'priorities' => [],
|
||||
];
|
||||
|
||||
foreach ($this->logger->getLogs($this->currentRequest) as $log) {
|
||||
if (isset($count['priorities'][$log['priority']])) {
|
||||
++$count['priorities'][$log['priority']]['count'];
|
||||
} else {
|
||||
$count['priorities'][$log['priority']] = [
|
||||
'count' => 1,
|
||||
'name' => $log['priorityName'],
|
||||
];
|
||||
}
|
||||
if ('WARNING' === $log['priorityName']) {
|
||||
++$count['warning_count'];
|
||||
}
|
||||
|
||||
if ($this->isSilencedOrDeprecationErrorLog($log)) {
|
||||
$exception = $log['context']['exception'];
|
||||
if ($exception instanceof SilencedErrorContext) {
|
||||
if (isset($silencedLogs[$h = spl_object_hash($exception)])) {
|
||||
continue;
|
||||
}
|
||||
$silencedLogs[$h] = true;
|
||||
$count['scream_count'] += $exception->count;
|
||||
} else {
|
||||
++$count['deprecation_count'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($containerDeprecationLogs as $deprecationLog) {
|
||||
$count['deprecation_count'] += $deprecationLog['context']['exception']->count;
|
||||
}
|
||||
|
||||
ksort($count['priorities']);
|
||||
|
||||
return $count;
|
||||
}
|
||||
}
|
95
vendor/symfony/http-kernel/DataCollector/MemoryDataCollector.php
vendored
Normal file
95
vendor/symfony/http-kernel/DataCollector/MemoryDataCollector.php
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
<?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\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class MemoryDataCollector extends DataCollector implements LateDataCollectorInterface
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
|
||||
{
|
||||
$this->updateMemoryUsage();
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
$this->data = [
|
||||
'memory' => 0,
|
||||
'memory_limit' => $this->convertToBytes(\ini_get('memory_limit')),
|
||||
];
|
||||
}
|
||||
|
||||
public function lateCollect(): void
|
||||
{
|
||||
$this->updateMemoryUsage();
|
||||
}
|
||||
|
||||
public function getMemory(): int
|
||||
{
|
||||
return $this->data['memory'];
|
||||
}
|
||||
|
||||
public function getMemoryLimit(): int|float
|
||||
{
|
||||
return $this->data['memory_limit'];
|
||||
}
|
||||
|
||||
public function updateMemoryUsage(): void
|
||||
{
|
||||
$this->data['memory'] = memory_get_peak_usage(true);
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'memory';
|
||||
}
|
||||
|
||||
private function convertToBytes(string $memoryLimit): int|float
|
||||
{
|
||||
if ('-1' === $memoryLimit) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
$memoryLimit = strtolower($memoryLimit);
|
||||
$max = strtolower(ltrim($memoryLimit, '+'));
|
||||
if (str_starts_with($max, '0x')) {
|
||||
$max = \intval($max, 16);
|
||||
} elseif (str_starts_with($max, '0')) {
|
||||
$max = \intval($max, 8);
|
||||
} else {
|
||||
$max = (int) $max;
|
||||
}
|
||||
|
||||
switch (substr($memoryLimit, -1)) {
|
||||
case 't': $max *= 1024;
|
||||
// no break
|
||||
case 'g': $max *= 1024;
|
||||
// no break
|
||||
case 'm': $max *= 1024;
|
||||
// no break
|
||||
case 'k': $max *= 1024;
|
||||
}
|
||||
|
||||
return $max;
|
||||
}
|
||||
}
|
535
vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php
vendored
Normal file
535
vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php
vendored
Normal file
@ -0,0 +1,535 @@
|
||||
<?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\DataCollector;
|
||||
|
||||
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\HttpFoundation\Session\SessionBagInterface;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
use Symfony\Component\HttpKernel\Event\ControllerEvent;
|
||||
use Symfony\Component\HttpKernel\Event\ResponseEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Component\VarDumper\Cloner\Data;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class RequestDataCollector extends DataCollector implements EventSubscriberInterface, LateDataCollectorInterface
|
||||
{
|
||||
/**
|
||||
* @var \SplObjectStorage<Request, callable>
|
||||
*/
|
||||
private \SplObjectStorage $controllers;
|
||||
private array $sessionUsages = [];
|
||||
private ?RequestStack $requestStack;
|
||||
|
||||
public function __construct(?RequestStack $requestStack = null)
|
||||
{
|
||||
$this->controllers = new \SplObjectStorage();
|
||||
$this->requestStack = $requestStack;
|
||||
}
|
||||
|
||||
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
|
||||
{
|
||||
// attributes are serialized and as they can be anything, they need to be converted to strings.
|
||||
$attributes = [];
|
||||
$route = '';
|
||||
foreach ($request->attributes->all() as $key => $value) {
|
||||
if ('_route' === $key) {
|
||||
$route = \is_object($value) ? $value->getPath() : $value;
|
||||
$attributes[$key] = $route;
|
||||
} else {
|
||||
$attributes[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$content = $request->getContent();
|
||||
|
||||
$sessionMetadata = [];
|
||||
$sessionAttributes = [];
|
||||
$flashes = [];
|
||||
if ($request->hasSession()) {
|
||||
$session = $request->getSession();
|
||||
if ($session->isStarted()) {
|
||||
$sessionMetadata['Created'] = date(\DATE_RFC822, $session->getMetadataBag()->getCreated());
|
||||
$sessionMetadata['Last used'] = date(\DATE_RFC822, $session->getMetadataBag()->getLastUsed());
|
||||
$sessionMetadata['Lifetime'] = $session->getMetadataBag()->getLifetime();
|
||||
$sessionAttributes = $session->all();
|
||||
$flashes = $session->getFlashBag()->peekAll();
|
||||
}
|
||||
}
|
||||
|
||||
$statusCode = $response->getStatusCode();
|
||||
|
||||
$responseCookies = [];
|
||||
foreach ($response->headers->getCookies() as $cookie) {
|
||||
$responseCookies[$cookie->getName()] = $cookie;
|
||||
}
|
||||
|
||||
$dotenvVars = [];
|
||||
foreach (explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? $_ENV['SYMFONY_DOTENV_VARS'] ?? '') as $name) {
|
||||
if ('' !== $name && isset($_ENV[$name])) {
|
||||
$dotenvVars[$name] = $_ENV[$name];
|
||||
}
|
||||
}
|
||||
|
||||
$this->data = [
|
||||
'method' => $request->getMethod(),
|
||||
'format' => $request->getRequestFormat(),
|
||||
'content_type' => $response->headers->get('Content-Type', 'text/html'),
|
||||
'status_text' => Response::$statusTexts[$statusCode] ?? '',
|
||||
'status_code' => $statusCode,
|
||||
'request_query' => $request->query->all(),
|
||||
'request_request' => $request->request->all(),
|
||||
'request_files' => $request->files->all(),
|
||||
'request_headers' => $request->headers->all(),
|
||||
'request_server' => $request->server->all(),
|
||||
'request_cookies' => $request->cookies->all(),
|
||||
'request_attributes' => $attributes,
|
||||
'route' => $route,
|
||||
'response_headers' => $response->headers->all(),
|
||||
'response_cookies' => $responseCookies,
|
||||
'session_metadata' => $sessionMetadata,
|
||||
'session_attributes' => $sessionAttributes,
|
||||
'session_usages' => array_values($this->sessionUsages),
|
||||
'stateless_check' => $this->requestStack?->getMainRequest()?->attributes->get('_stateless') ?? false,
|
||||
'flashes' => $flashes,
|
||||
'path_info' => $request->getPathInfo(),
|
||||
'controller' => 'n/a',
|
||||
'locale' => $request->getLocale(),
|
||||
'dotenv_vars' => $dotenvVars,
|
||||
];
|
||||
|
||||
if (isset($this->data['request_headers']['php-auth-pw'])) {
|
||||
$this->data['request_headers']['php-auth-pw'] = '******';
|
||||
}
|
||||
|
||||
if (isset($this->data['request_server']['PHP_AUTH_PW'])) {
|
||||
$this->data['request_server']['PHP_AUTH_PW'] = '******';
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if ('request_headers' === $key || 'response_headers' === $key) {
|
||||
$this->data[$key] = array_map(fn ($v) => isset($v[0]) && !isset($v[1]) ? $v[0] : $v, $value);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->controllers[$request])) {
|
||||
$this->data['controller'] = $this->parseController($this->controllers[$request]);
|
||||
unset($this->controllers[$request]);
|
||||
}
|
||||
|
||||
if ($request->attributes->has('_redirected') && $redirectCookie = $request->cookies->get('sf_redirect')) {
|
||||
$this->data['redirect'] = json_decode($redirectCookie, true);
|
||||
|
||||
$response->headers->clearCookie('sf_redirect');
|
||||
}
|
||||
|
||||
if ($response->isRedirect()) {
|
||||
$response->headers->setCookie(new Cookie(
|
||||
'sf_redirect',
|
||||
json_encode([
|
||||
'token' => $response->headers->get('x-debug-token'),
|
||||
'route' => $request->attributes->get('_route', 'n/a'),
|
||||
'method' => $request->getMethod(),
|
||||
'controller' => $this->parseController($request->attributes->get('_controller')),
|
||||
'status_code' => $statusCode,
|
||||
'status_text' => Response::$statusTexts[$statusCode],
|
||||
]),
|
||||
0, '/', null, $request->isSecure(), true, false, 'lax'
|
||||
));
|
||||
}
|
||||
|
||||
$this->data['identifier'] = $this->data['route'] ?: (\is_array($this->data['controller']) ? $this->data['controller']['class'].'::'.$this->data['controller']['method'].'()' : $this->data['controller']);
|
||||
|
||||
if ($response->headers->has('x-previous-debug-token')) {
|
||||
$this->data['forward_token'] = $response->headers->get('x-previous-debug-token');
|
||||
}
|
||||
}
|
||||
|
||||
public function lateCollect(): void
|
||||
{
|
||||
$this->data = $this->cloneVar($this->data);
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
parent::reset();
|
||||
$this->controllers = new \SplObjectStorage();
|
||||
$this->sessionUsages = [];
|
||||
}
|
||||
|
||||
public function getMethod(): string
|
||||
{
|
||||
return $this->data['method'];
|
||||
}
|
||||
|
||||
public function getPathInfo(): string
|
||||
{
|
||||
return $this->data['path_info'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ParameterBag
|
||||
*/
|
||||
public function getRequestRequest()
|
||||
{
|
||||
return new ParameterBag($this->data['request_request']->getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ParameterBag
|
||||
*/
|
||||
public function getRequestQuery()
|
||||
{
|
||||
return new ParameterBag($this->data['request_query']->getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ParameterBag
|
||||
*/
|
||||
public function getRequestFiles()
|
||||
{
|
||||
return new ParameterBag($this->data['request_files']->getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ParameterBag
|
||||
*/
|
||||
public function getRequestHeaders()
|
||||
{
|
||||
return new ParameterBag($this->data['request_headers']->getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ParameterBag
|
||||
*/
|
||||
public function getRequestServer(bool $raw = false)
|
||||
{
|
||||
return new ParameterBag($this->data['request_server']->getValue($raw));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ParameterBag
|
||||
*/
|
||||
public function getRequestCookies(bool $raw = false)
|
||||
{
|
||||
return new ParameterBag($this->data['request_cookies']->getValue($raw));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ParameterBag
|
||||
*/
|
||||
public function getRequestAttributes()
|
||||
{
|
||||
return new ParameterBag($this->data['request_attributes']->getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ParameterBag
|
||||
*/
|
||||
public function getResponseHeaders()
|
||||
{
|
||||
return new ParameterBag($this->data['response_headers']->getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ParameterBag
|
||||
*/
|
||||
public function getResponseCookies()
|
||||
{
|
||||
return new ParameterBag($this->data['response_cookies']->getValue());
|
||||
}
|
||||
|
||||
public function getSessionMetadata(): array
|
||||
{
|
||||
return $this->data['session_metadata']->getValue();
|
||||
}
|
||||
|
||||
public function getSessionAttributes(): array
|
||||
{
|
||||
return $this->data['session_attributes']->getValue();
|
||||
}
|
||||
|
||||
public function getStatelessCheck(): bool
|
||||
{
|
||||
return $this->data['stateless_check'];
|
||||
}
|
||||
|
||||
public function getSessionUsages(): Data|array
|
||||
{
|
||||
return $this->data['session_usages'];
|
||||
}
|
||||
|
||||
public function getFlashes(): array
|
||||
{
|
||||
return $this->data['flashes']->getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|resource
|
||||
*/
|
||||
public function getContent()
|
||||
{
|
||||
return $this->data['content'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isJsonRequest()
|
||||
{
|
||||
return 1 === preg_match('{^application/(?:\w+\++)*json$}i', $this->data['request_headers']['content-type']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPrettyJson()
|
||||
{
|
||||
$decoded = json_decode($this->getContent());
|
||||
|
||||
return \JSON_ERROR_NONE === json_last_error() ? json_encode($decoded, \JSON_PRETTY_PRINT) : null;
|
||||
}
|
||||
|
||||
public function getContentType(): string
|
||||
{
|
||||
return $this->data['content_type'];
|
||||
}
|
||||
|
||||
public function getStatusText(): string
|
||||
{
|
||||
return $this->data['status_text'];
|
||||
}
|
||||
|
||||
public function getStatusCode(): int
|
||||
{
|
||||
return $this->data['status_code'];
|
||||
}
|
||||
|
||||
public function getFormat(): string
|
||||
{
|
||||
return $this->data['format'];
|
||||
}
|
||||
|
||||
public function getLocale(): string
|
||||
{
|
||||
return $this->data['locale'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ParameterBag
|
||||
*/
|
||||
public function getDotenvVars()
|
||||
{
|
||||
return new ParameterBag($this->data['dotenv_vars']->getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the route name.
|
||||
*
|
||||
* The _route request attributes is automatically set by the Router Matcher.
|
||||
*/
|
||||
public function getRoute(): string
|
||||
{
|
||||
return $this->data['route'];
|
||||
}
|
||||
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return $this->data['identifier'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the route parameters.
|
||||
*
|
||||
* The _route_params request attributes is automatically set by the RouterListener.
|
||||
*/
|
||||
public function getRouteParams(): array
|
||||
{
|
||||
return isset($this->data['request_attributes']['_route_params']) ? $this->data['request_attributes']['_route_params']->getValue() : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the parsed controller.
|
||||
*
|
||||
* @return array|string|Data The controller as a string or array of data
|
||||
* with keys 'class', 'method', 'file' and 'line'
|
||||
*/
|
||||
public function getController(): array|string|Data
|
||||
{
|
||||
return $this->data['controller'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the previous request attributes.
|
||||
*
|
||||
* @return array|Data|false A legacy array of data from the previous redirection response
|
||||
* or false otherwise
|
||||
*/
|
||||
public function getRedirect(): array|Data|false
|
||||
{
|
||||
return $this->data['redirect'] ?? false;
|
||||
}
|
||||
|
||||
public function getForwardToken(): ?string
|
||||
{
|
||||
return $this->data['forward_token'] ?? null;
|
||||
}
|
||||
|
||||
public function onKernelController(ControllerEvent $event): void
|
||||
{
|
||||
$this->controllers[$event->getRequest()] = $event->getController();
|
||||
}
|
||||
|
||||
public function onKernelResponse(ResponseEvent $event): void
|
||||
{
|
||||
if (!$event->isMainRequest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($event->getRequest()->cookies->has('sf_redirect')) {
|
||||
$event->getRequest()->attributes->set('_redirected', true);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
KernelEvents::CONTROLLER => 'onKernelController',
|
||||
KernelEvents::RESPONSE => 'onKernelResponse',
|
||||
];
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'request';
|
||||
}
|
||||
|
||||
public function collectSessionUsage(): void
|
||||
{
|
||||
$trace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
|
||||
$traceEndIndex = \count($trace) - 1;
|
||||
for ($i = $traceEndIndex; $i > 0; --$i) {
|
||||
if (null !== ($class = $trace[$i]['class'] ?? null) && (is_subclass_of($class, SessionInterface::class) || is_subclass_of($class, SessionBagInterface::class))) {
|
||||
$traceEndIndex = $i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((\count($trace) - 1) === $traceEndIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove part of the backtrace that belongs to session only
|
||||
array_splice($trace, 0, $traceEndIndex);
|
||||
|
||||
// Merge identical backtraces generated by internal call reports
|
||||
$name = sprintf('%s:%s', $trace[1]['class'] ?? $trace[0]['file'], $trace[0]['line']);
|
||||
if (!\array_key_exists($name, $this->sessionUsages)) {
|
||||
$this->sessionUsages[$name] = [
|
||||
'name' => $name,
|
||||
'file' => $trace[0]['file'],
|
||||
'line' => $trace[0]['line'],
|
||||
'trace' => $trace,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|string An array of controller data or a simple string
|
||||
*/
|
||||
private function parseController(array|object|string|null $controller): array|string
|
||||
{
|
||||
if (\is_string($controller) && str_contains($controller, '::')) {
|
||||
$controller = explode('::', $controller);
|
||||
}
|
||||
|
||||
if (\is_array($controller)) {
|
||||
try {
|
||||
$r = new \ReflectionMethod($controller[0], $controller[1]);
|
||||
|
||||
return [
|
||||
'class' => \is_object($controller[0]) ? get_debug_type($controller[0]) : $controller[0],
|
||||
'method' => $controller[1],
|
||||
'file' => $r->getFileName(),
|
||||
'line' => $r->getStartLine(),
|
||||
];
|
||||
} catch (\ReflectionException) {
|
||||
if (\is_callable($controller)) {
|
||||
// using __call or __callStatic
|
||||
return [
|
||||
'class' => \is_object($controller[0]) ? get_debug_type($controller[0]) : $controller[0],
|
||||
'method' => $controller[1],
|
||||
'file' => 'n/a',
|
||||
'line' => 'n/a',
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($controller instanceof \Closure) {
|
||||
$r = new \ReflectionFunction($controller);
|
||||
|
||||
$controller = [
|
||||
'class' => $r->getName(),
|
||||
'method' => null,
|
||||
'file' => $r->getFileName(),
|
||||
'line' => $r->getStartLine(),
|
||||
];
|
||||
|
||||
if (str_contains($r->name, '{closure}')) {
|
||||
return $controller;
|
||||
}
|
||||
$controller['method'] = $r->name;
|
||||
|
||||
if ($class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) {
|
||||
$controller['class'] = $class->name;
|
||||
} else {
|
||||
return $r->name;
|
||||
}
|
||||
|
||||
return $controller;
|
||||
}
|
||||
|
||||
if (\is_object($controller)) {
|
||||
$r = new \ReflectionClass($controller);
|
||||
|
||||
return [
|
||||
'class' => $r->getName(),
|
||||
'method' => null,
|
||||
'file' => $r->getFileName(),
|
||||
'line' => $r->getStartLine(),
|
||||
];
|
||||
}
|
||||
|
||||
return \is_string($controller) ? $controller : 'n/a';
|
||||
}
|
||||
}
|
105
vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php
vendored
Normal file
105
vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
<?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\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\ControllerEvent;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class RouterDataCollector extends DataCollector
|
||||
{
|
||||
/**
|
||||
* @var \SplObjectStorage<Request, callable>
|
||||
*/
|
||||
protected $controllers;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
|
||||
{
|
||||
if ($response instanceof RedirectResponse) {
|
||||
$this->data['redirect'] = true;
|
||||
$this->data['url'] = $response->getTargetUrl();
|
||||
|
||||
if ($this->controllers->contains($request)) {
|
||||
$this->data['route'] = $this->guessRoute($request, $this->controllers[$request]);
|
||||
}
|
||||
}
|
||||
|
||||
unset($this->controllers[$request]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->controllers = new \SplObjectStorage();
|
||||
|
||||
$this->data = [
|
||||
'redirect' => false,
|
||||
'url' => null,
|
||||
'route' => null,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function guessRoute(Request $request, string|object|array $controller)
|
||||
{
|
||||
return 'n/a';
|
||||
}
|
||||
|
||||
/**
|
||||
* Remembers the controller associated to each request.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onKernelController(ControllerEvent $event)
|
||||
{
|
||||
$this->controllers[$event->getRequest()] = $event->getController();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool Whether this request will result in a redirect
|
||||
*/
|
||||
public function getRedirect(): bool
|
||||
{
|
||||
return $this->data['redirect'];
|
||||
}
|
||||
|
||||
public function getTargetUrl(): ?string
|
||||
{
|
||||
return $this->data['url'];
|
||||
}
|
||||
|
||||
public function getTargetRoute(): ?string
|
||||
{
|
||||
return $this->data['route'];
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'router';
|
||||
}
|
||||
}
|
130
vendor/symfony/http-kernel/DataCollector/TimeDataCollector.php
vendored
Normal file
130
vendor/symfony/http-kernel/DataCollector/TimeDataCollector.php
vendored
Normal file
@ -0,0 +1,130 @@
|
||||
<?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\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use Symfony\Component\Stopwatch\Stopwatch;
|
||||
use Symfony\Component\Stopwatch\StopwatchEvent;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class TimeDataCollector extends DataCollector implements LateDataCollectorInterface
|
||||
{
|
||||
private ?KernelInterface $kernel;
|
||||
private ?Stopwatch $stopwatch;
|
||||
|
||||
public function __construct(?KernelInterface $kernel = null, ?Stopwatch $stopwatch = null)
|
||||
{
|
||||
$this->kernel = $kernel;
|
||||
$this->stopwatch = $stopwatch;
|
||||
$this->data = ['events' => [], 'stopwatch_installed' => false, 'start_time' => 0];
|
||||
}
|
||||
|
||||
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
|
||||
{
|
||||
if (null !== $this->kernel) {
|
||||
$startTime = $this->kernel->getStartTime();
|
||||
} else {
|
||||
$startTime = $request->server->get('REQUEST_TIME_FLOAT');
|
||||
}
|
||||
|
||||
$this->data = [
|
||||
'token' => $request->attributes->get('_stopwatch_token'),
|
||||
'start_time' => $startTime * 1000,
|
||||
'events' => [],
|
||||
'stopwatch_installed' => class_exists(Stopwatch::class, false),
|
||||
];
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
$this->data = ['events' => [], 'stopwatch_installed' => false, 'start_time' => 0];
|
||||
|
||||
$this->stopwatch?->reset();
|
||||
}
|
||||
|
||||
public function lateCollect(): void
|
||||
{
|
||||
if (null !== $this->stopwatch && isset($this->data['token'])) {
|
||||
$this->setEvents($this->stopwatch->getSectionEvents($this->data['token']));
|
||||
}
|
||||
unset($this->data['token']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StopwatchEvent[] $events The request events
|
||||
*/
|
||||
public function setEvents(array $events): void
|
||||
{
|
||||
foreach ($events as $event) {
|
||||
$event->ensureStopped();
|
||||
}
|
||||
|
||||
$this->data['events'] = $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return StopwatchEvent[]
|
||||
*/
|
||||
public function getEvents(): array
|
||||
{
|
||||
return $this->data['events'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the request elapsed time.
|
||||
*/
|
||||
public function getDuration(): float
|
||||
{
|
||||
if (!isset($this->data['events']['__section__'])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$lastEvent = $this->data['events']['__section__'];
|
||||
|
||||
return $lastEvent->getOrigin() + $lastEvent->getDuration() - $this->getStartTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the initialization time.
|
||||
*
|
||||
* This is the time spent until the beginning of the request handling.
|
||||
*/
|
||||
public function getInitTime(): float
|
||||
{
|
||||
if (!isset($this->data['events']['__section__'])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $this->data['events']['__section__']->getOrigin() - $this->getStartTime();
|
||||
}
|
||||
|
||||
public function getStartTime(): float
|
||||
{
|
||||
return $this->data['start_time'];
|
||||
}
|
||||
|
||||
public function isStopwatchInstalled(): bool
|
||||
{
|
||||
return $this->data['stopwatch_installed'];
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'time';
|
||||
}
|
||||
}
|
107
vendor/symfony/http-kernel/Debug/ErrorHandlerConfigurator.php
vendored
Normal file
107
vendor/symfony/http-kernel/Debug/ErrorHandlerConfigurator.php
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
<?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\Debug;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\ErrorHandler\ErrorHandler;
|
||||
|
||||
/**
|
||||
* Configures the error handler.
|
||||
*
|
||||
* @final
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ErrorHandlerConfigurator
|
||||
{
|
||||
private ?LoggerInterface $logger;
|
||||
private ?LoggerInterface $deprecationLogger;
|
||||
private array|int|null $levels;
|
||||
private ?int $throwAt;
|
||||
private bool $scream;
|
||||
private bool $scope;
|
||||
|
||||
/**
|
||||
* @param array|int|null $levels An array map of E_* to LogLevel::* or an integer bit field of E_* constants
|
||||
* @param int|null $throwAt Thrown errors in a bit field of E_* constants, or null to keep the current value
|
||||
* @param bool $scream Enables/disables screaming mode, where even silenced errors are logged
|
||||
* @param bool $scope Enables/disables scoping mode
|
||||
*/
|
||||
public function __construct(?LoggerInterface $logger = null, array|int|null $levels = \E_ALL, ?int $throwAt = \E_ALL, bool $scream = true, bool $scope = true, ?LoggerInterface $deprecationLogger = null)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->levels = $levels ?? \E_ALL;
|
||||
$this->throwAt = \is_int($throwAt) ? $throwAt : (null === $throwAt ? null : ($throwAt ? \E_ALL : null));
|
||||
$this->scream = $scream;
|
||||
$this->scope = $scope;
|
||||
$this->deprecationLogger = $deprecationLogger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the error handler.
|
||||
*/
|
||||
public function configure(ErrorHandler $handler): void
|
||||
{
|
||||
if ($this->logger || $this->deprecationLogger) {
|
||||
$this->setDefaultLoggers($handler);
|
||||
if (\is_array($this->levels)) {
|
||||
$levels = 0;
|
||||
foreach ($this->levels as $type => $log) {
|
||||
$levels |= $type;
|
||||
}
|
||||
} else {
|
||||
$levels = $this->levels;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
31
vendor/symfony/http-kernel/Debug/FileLinkFormatter.php
vendored
Normal file
31
vendor/symfony/http-kernel/Debug/FileLinkFormatter.php
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Debug;
|
||||
|
||||
use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter as ErrorHandlerFileLinkFormatter;
|
||||
|
||||
trigger_deprecation('symfony/http-kernel', '6.4', 'The "%s" class is deprecated, use "%s" instead.', FileLinkFormatter::class, ErrorHandlerFileLinkFormatter::class);
|
||||
|
||||
class_exists(ErrorHandlerFileLinkFormatter::class);
|
||||
|
||||
if (!class_exists(FileLinkFormatter::class, false)) {
|
||||
class_alias(ErrorHandlerFileLinkFormatter::class, FileLinkFormatter::class);
|
||||
}
|
||||
|
||||
if (false) {
|
||||
/**
|
||||
* @deprecated since Symfony 6.4, use FileLinkFormatter from the ErrorHandler component instead
|
||||
*/
|
||||
class FileLinkFormatter extends ErrorHandlerFileLinkFormatter
|
||||
{
|
||||
}
|
||||
}
|
85
vendor/symfony/http-kernel/Debug/TraceableEventDispatcher.php
vendored
Normal file
85
vendor/symfony/http-kernel/Debug/TraceableEventDispatcher.php
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
<?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\Debug;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher as BaseTraceableEventDispatcher;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
|
||||
/**
|
||||
* Collects some data about event listeners.
|
||||
*
|
||||
* This event dispatcher delegates the dispatching to another one.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class TraceableEventDispatcher extends BaseTraceableEventDispatcher
|
||||
{
|
||||
protected function beforeDispatch(string $eventName, object $event): void
|
||||
{
|
||||
switch ($eventName) {
|
||||
case KernelEvents::REQUEST:
|
||||
$event->getRequest()->attributes->set('_stopwatch_token', substr(hash('sha256', uniqid(mt_rand(), true)), 0, 6));
|
||||
$this->stopwatch->openSection();
|
||||
break;
|
||||
case KernelEvents::VIEW:
|
||||
case KernelEvents::RESPONSE:
|
||||
// stop only if a controller has been executed
|
||||
if ($this->stopwatch->isStarted('controller')) {
|
||||
$this->stopwatch->stop('controller');
|
||||
}
|
||||
break;
|
||||
case KernelEvents::TERMINATE:
|
||||
$sectionId = $event->getRequest()->attributes->get('_stopwatch_token');
|
||||
if (null === $sectionId) {
|
||||
break;
|
||||
}
|
||||
// There is a very special case when using built-in AppCache class as kernel wrapper, in the case
|
||||
// of an ESI request leading to a `stale` response [B] inside a `fresh` cached response [A].
|
||||
// In this case, `$token` contains the [B] debug token, but the open `stopwatch` section ID
|
||||
// is equal to the [A] debug token. Trying to reopen section with the [B] token throws an exception
|
||||
// which must be caught.
|
||||
try {
|
||||
$this->stopwatch->openSection($sectionId);
|
||||
} catch (\LogicException) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function afterDispatch(string $eventName, object $event): void
|
||||
{
|
||||
switch ($eventName) {
|
||||
case KernelEvents::CONTROLLER_ARGUMENTS:
|
||||
$this->stopwatch->start('controller', 'section');
|
||||
break;
|
||||
case KernelEvents::RESPONSE:
|
||||
$sectionId = $event->getRequest()->attributes->get('_stopwatch_token');
|
||||
if (null === $sectionId) {
|
||||
break;
|
||||
}
|
||||
$this->stopwatch->stopSection($sectionId);
|
||||
break;
|
||||
case KernelEvents::TERMINATE:
|
||||
// In the special case described in the `preDispatch` method above, the `$token` section
|
||||
// does not exist, then closing it throws an exception which must be caught.
|
||||
$sectionId = $event->getRequest()->attributes->get('_stopwatch_token');
|
||||
if (null === $sectionId) {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
$this->stopwatch->stopSection($sectionId);
|
||||
} catch (\LogicException) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
65
vendor/symfony/http-kernel/Debug/VirtualRequestStack.php
vendored
Normal file
65
vendor/symfony/http-kernel/Debug/VirtualRequestStack.php
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
<?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\Debug;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
/**
|
||||
* A stack able to deal with virtual requests.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @author Jules Pietri <jules@heahprod.com>
|
||||
*/
|
||||
final class VirtualRequestStack extends RequestStack
|
||||
{
|
||||
public function __construct(
|
||||
private readonly RequestStack $decorated,
|
||||
) {
|
||||
}
|
||||
|
||||
public function push(Request $request): void
|
||||
{
|
||||
if ($request->attributes->has('_virtual_type')) {
|
||||
if ($this->decorated->getCurrentRequest()) {
|
||||
throw new \LogicException('Cannot mix virtual and HTTP requests.');
|
||||
}
|
||||
|
||||
parent::push($request);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->decorated->push($request);
|
||||
}
|
||||
|
||||
public function pop(): ?Request
|
||||
{
|
||||
return $this->decorated->pop() ?? parent::pop();
|
||||
}
|
||||
|
||||
public function getCurrentRequest(): ?Request
|
||||
{
|
||||
return $this->decorated->getCurrentRequest() ?? parent::getCurrentRequest();
|
||||
}
|
||||
|
||||
public function getMainRequest(): ?Request
|
||||
{
|
||||
return $this->decorated->getMainRequest() ?? parent::getMainRequest();
|
||||
}
|
||||
|
||||
public function getParentRequest(): ?Request
|
||||
{
|
||||
return $this->decorated->getParentRequest() ?? parent::getParentRequest();
|
||||
}
|
||||
}
|
145
vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php
vendored
Normal file
145
vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DependencyInjection;
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\ErrorHandler\DebugClassLoader;
|
||||
use Symfony\Component\HttpKernel\Kernel;
|
||||
|
||||
/**
|
||||
* Sets the classes to compile in the cache for the container.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class AddAnnotatedClassesToCachePass implements CompilerPassInterface
|
||||
{
|
||||
private Kernel $kernel;
|
||||
|
||||
public function __construct(Kernel $kernel)
|
||||
{
|
||||
$this->kernel = $kernel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$annotatedClasses = [];
|
||||
foreach ($container->getExtensions() as $extension) {
|
||||
if ($extension instanceof Extension) {
|
||||
$annotatedClasses[] = $extension->getAnnotatedClassesToCompile();
|
||||
}
|
||||
}
|
||||
|
||||
$annotatedClasses = array_merge($this->kernel->getAnnotatedClassesToCompile(), ...$annotatedClasses);
|
||||
|
||||
$existingClasses = $this->getClassesInComposerClassMaps();
|
||||
|
||||
$annotatedClasses = $container->getParameterBag()->resolveValue($annotatedClasses);
|
||||
$this->kernel->setAnnotatedClassCache($this->expandClasses($annotatedClasses, $existingClasses));
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands the given class patterns using a list of existing classes.
|
||||
*
|
||||
* @param array $patterns The class patterns to expand
|
||||
* @param array $classes The existing classes to match against the patterns
|
||||
*/
|
||||
private function expandClasses(array $patterns, array $classes): array
|
||||
{
|
||||
$expanded = [];
|
||||
|
||||
// Explicit classes declared in the patterns are returned directly
|
||||
foreach ($patterns as $key => $pattern) {
|
||||
if (!str_ends_with($pattern, '\\') && !str_contains($pattern, '*')) {
|
||||
unset($patterns[$key]);
|
||||
$expanded[] = ltrim($pattern, '\\');
|
||||
}
|
||||
}
|
||||
|
||||
// Match patterns with the classes list
|
||||
$regexps = $this->patternsToRegexps($patterns);
|
||||
|
||||
foreach ($classes as $class) {
|
||||
$class = ltrim($class, '\\');
|
||||
|
||||
if ($this->matchAnyRegexps($class, $regexps)) {
|
||||
$expanded[] = $class;
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique($expanded);
|
||||
}
|
||||
|
||||
private function getClassesInComposerClassMaps(): array
|
||||
{
|
||||
$classes = [];
|
||||
|
||||
foreach (spl_autoload_functions() as $function) {
|
||||
if (!\is_array($function)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($function[0] instanceof DebugClassLoader) {
|
||||
$function = $function[0]->getClassLoader();
|
||||
}
|
||||
|
||||
if (\is_array($function) && $function[0] instanceof ClassLoader) {
|
||||
$classes += array_filter($function[0]->getClassMap());
|
||||
}
|
||||
}
|
||||
|
||||
return array_keys($classes);
|
||||
}
|
||||
|
||||
private function patternsToRegexps(array $patterns): array
|
||||
{
|
||||
$regexps = [];
|
||||
|
||||
foreach ($patterns as $pattern) {
|
||||
// Escape user input
|
||||
$regex = preg_quote(ltrim($pattern, '\\'));
|
||||
|
||||
// Wildcards * and **
|
||||
$regex = strtr($regex, ['\\*\\*' => '.*?', '\\*' => '[^\\\\]*?']);
|
||||
|
||||
// If this class does not end by a slash, anchor the end
|
||||
if (!str_ends_with($regex, '\\')) {
|
||||
$regex .= '$';
|
||||
}
|
||||
|
||||
$regexps[] = '{^\\\\'.$regex.'}';
|
||||
}
|
||||
|
||||
return $regexps;
|
||||
}
|
||||
|
||||
private function matchAnyRegexps(string $class, array $regexps): bool
|
||||
{
|
||||
$isTest = str_contains($class, 'Test');
|
||||
|
||||
foreach ($regexps as $regex) {
|
||||
if ($isTest && !str_contains($regex, 'Test')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (preg_match($regex, '\\'.$class)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
41
vendor/symfony/http-kernel/DependencyInjection/ConfigurableExtension.php
vendored
Normal file
41
vendor/symfony/http-kernel/DependencyInjection/ConfigurableExtension.php
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* This extension sub-class provides first-class integration with the
|
||||
* Config/Definition Component.
|
||||
*
|
||||
* You can use this as base class if
|
||||
*
|
||||
* a) you use the Config/Definition component for configuration,
|
||||
* b) your configuration class is named "Configuration", and
|
||||
* c) the configuration class resides in the DependencyInjection sub-folder.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
abstract class ConfigurableExtension extends Extension
|
||||
{
|
||||
final public function load(array $configs, ContainerBuilder $container): void
|
||||
{
|
||||
$this->loadInternal($this->processConfiguration($this->getConfiguration($configs, $container), $configs), $container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the passed container according to the merged configuration.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function loadInternal(array $mergedConfig, ContainerBuilder $container);
|
||||
}
|
73
vendor/symfony/http-kernel/DependencyInjection/ControllerArgumentValueResolverPass.php
vendored
Normal file
73
vendor/symfony/http-kernel/DependencyInjection/ControllerArgumentValueResolverPass.php
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver;
|
||||
use Symfony\Component\Stopwatch\Stopwatch;
|
||||
|
||||
/**
|
||||
* Gathers and configures the argument value resolvers.
|
||||
*
|
||||
* @author Iltar van der Berg <kjarli@gmail.com>
|
||||
*/
|
||||
class ControllerArgumentValueResolverPass implements CompilerPassInterface
|
||||
{
|
||||
use PriorityTaggedServiceTrait;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition('argument_resolver')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$definitions = $container->getDefinitions();
|
||||
$namedResolvers = $this->findAndSortTaggedServices(new TaggedIteratorArgument('controller.targeted_value_resolver', 'name', needsIndexes: true), $container);
|
||||
$resolvers = $this->findAndSortTaggedServices(new TaggedIteratorArgument('controller.argument_value_resolver', 'name', needsIndexes: true), $container);
|
||||
|
||||
foreach ($resolvers as $name => $resolver) {
|
||||
if ($definitions[(string) $resolver]->hasTag('controller.targeted_value_resolver')) {
|
||||
unset($resolvers[$name]);
|
||||
} else {
|
||||
$namedResolvers[$name] ??= clone $resolver;
|
||||
}
|
||||
}
|
||||
|
||||
if ($container->getParameter('kernel.debug') && class_exists(Stopwatch::class) && $container->has('debug.stopwatch')) {
|
||||
foreach ($resolvers as $name => $resolver) {
|
||||
$resolvers[$name] = new Reference('.debug.value_resolver.'.$resolver);
|
||||
$container->register('.debug.value_resolver.'.$resolver, TraceableValueResolver::class)
|
||||
->setArguments([$resolver, new Reference('debug.stopwatch')]);
|
||||
}
|
||||
foreach ($namedResolvers as $name => $resolver) {
|
||||
$namedResolvers[$name] = new Reference('.debug.value_resolver.'.$resolver);
|
||||
$container->register('.debug.value_resolver.'.$resolver, TraceableValueResolver::class)
|
||||
->setArguments([$resolver, new Reference('debug.stopwatch')]);
|
||||
}
|
||||
}
|
||||
|
||||
$container
|
||||
->getDefinition('argument_resolver')
|
||||
->replaceArgument(1, new IteratorArgument(array_values($resolvers)))
|
||||
->setArgument(2, new ServiceLocatorArgument($namedResolvers))
|
||||
;
|
||||
}
|
||||
}
|
44
vendor/symfony/http-kernel/DependencyInjection/Extension.php
vendored
Normal file
44
vendor/symfony/http-kernel/DependencyInjection/Extension.php
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Extension\Extension as BaseExtension;
|
||||
|
||||
/**
|
||||
* Allow adding classes to the class cache.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
abstract class Extension extends BaseExtension
|
||||
{
|
||||
private array $annotatedClasses = [];
|
||||
|
||||
/**
|
||||
* Gets the annotated classes to cache.
|
||||
*/
|
||||
public function getAnnotatedClassesToCompile(): array
|
||||
{
|
||||
return $this->annotatedClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds annotated classes to the class cache.
|
||||
*
|
||||
* @param array $annotatedClasses An array of class patterns
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addAnnotatedClassesToCompile(array $annotatedClasses)
|
||||
{
|
||||
$this->annotatedClasses = array_merge($this->annotatedClasses, $annotatedClasses);
|
||||
}
|
||||
}
|
57
vendor/symfony/http-kernel/DependencyInjection/FragmentRendererPass.php
vendored
Normal file
57
vendor/symfony/http-kernel/DependencyInjection/FragmentRendererPass.php
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface;
|
||||
|
||||
/**
|
||||
* Adds services tagged kernel.fragment_renderer as HTTP content rendering strategies.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class FragmentRendererPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition('fragment.handler')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$definition = $container->getDefinition('fragment.handler');
|
||||
$renderers = [];
|
||||
foreach ($container->findTaggedServiceIds('kernel.fragment_renderer', true) as $id => $tags) {
|
||||
$def = $container->getDefinition($id);
|
||||
$class = $container->getParameterBag()->resolveValue($def->getClass());
|
||||
|
||||
if (!$r = $container->getReflectionClass($class)) {
|
||||
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
|
||||
}
|
||||
if (!$r->isSubclassOf(FragmentRendererInterface::class)) {
|
||||
throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, FragmentRendererInterface::class));
|
||||
}
|
||||
|
||||
foreach ($tags as $tag) {
|
||||
$renderers[$tag['alias']] = new Reference($id);
|
||||
}
|
||||
}
|
||||
|
||||
$definition->replaceArgument(0, ServiceLocatorTagPass::register($container, $renderers));
|
||||
}
|
||||
}
|
49
vendor/symfony/http-kernel/DependencyInjection/LazyLoadingFragmentHandler.php
vendored
Normal file
49
vendor/symfony/http-kernel/DependencyInjection/LazyLoadingFragmentHandler.php
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DependencyInjection;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpKernel\Controller\ControllerReference;
|
||||
use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
|
||||
|
||||
/**
|
||||
* Lazily loads fragment renderers from the dependency injection container.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class LazyLoadingFragmentHandler extends FragmentHandler
|
||||
{
|
||||
private ContainerInterface $container;
|
||||
|
||||
/**
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private array $initialized = [];
|
||||
|
||||
public function __construct(ContainerInterface $container, RequestStack $requestStack, bool $debug = false)
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
parent::__construct($requestStack, [], $debug);
|
||||
}
|
||||
|
||||
public function render(string|ControllerReference $uri, string $renderer = 'inline', array $options = []): ?string
|
||||
{
|
||||
if (!isset($this->initialized[$renderer]) && $this->container->has($renderer)) {
|
||||
$this->addRenderer($this->container->get($renderer));
|
||||
$this->initialized[$renderer] = true;
|
||||
}
|
||||
|
||||
return parent::render($uri, $renderer, $options);
|
||||
}
|
||||
}
|
48
vendor/symfony/http-kernel/DependencyInjection/LoggerPass.php
vendored
Normal file
48
vendor/symfony/http-kernel/DependencyInjection/LoggerPass.php
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DependencyInjection;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpKernel\Log\Logger;
|
||||
|
||||
/**
|
||||
* Registers the default logger if necessary.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class LoggerPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$container->setAlias(LoggerInterface::class, 'logger');
|
||||
|
||||
if ($container->has('logger')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($debug = $container->getParameter('kernel.debug')) {
|
||||
$debug = $container->hasParameter('kernel.runtime_mode.web')
|
||||
? $container->getParameter('kernel.runtime_mode.web')
|
||||
: !\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true);
|
||||
}
|
||||
|
||||
$container->register('logger', Logger::class)
|
||||
->setArguments([null, null, null, new Reference(RequestStack::class), $debug]);
|
||||
}
|
||||
}
|
44
vendor/symfony/http-kernel/DependencyInjection/MergeExtensionConfigurationPass.php
vendored
Normal file
44
vendor/symfony/http-kernel/DependencyInjection/MergeExtensionConfigurationPass.php
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationPass as BaseMergeExtensionConfigurationPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Ensures certain extensions are always loaded.
|
||||
*
|
||||
* @author Kris Wallsmith <kris@symfony.com>
|
||||
*/
|
||||
class MergeExtensionConfigurationPass extends BaseMergeExtensionConfigurationPass
|
||||
{
|
||||
private array $extensions;
|
||||
|
||||
/**
|
||||
* @param string[] $extensions
|
||||
*/
|
||||
public function __construct(array $extensions)
|
||||
{
|
||||
$this->extensions = $extensions;
|
||||
}
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
foreach ($this->extensions as $extension) {
|
||||
if (!\count($container->getExtensionConfig($extension))) {
|
||||
$container->loadFromExtension($extension, []);
|
||||
}
|
||||
}
|
||||
|
||||
parent::process($container);
|
||||
}
|
||||
}
|
239
vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php
vendored
Normal file
239
vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php
vendored
Normal file
@ -0,0 +1,239 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use Symfony\Component\DependencyInjection\Attribute\AutowireCallable;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Target;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\TypedReference;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
use Symfony\Component\VarExporter\ProxyHelper;
|
||||
|
||||
/**
|
||||
* Creates the service-locators required by ServiceValueResolver.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition('argument_resolver.service') && !$container->hasDefinition('argument_resolver.not_tagged_controller')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$parameterBag = $container->getParameterBag();
|
||||
$controllers = [];
|
||||
$controllerClasses = [];
|
||||
|
||||
$publicAliases = [];
|
||||
foreach ($container->getAliases() as $id => $alias) {
|
||||
if ($alias->isPublic() && !$alias->isPrivate()) {
|
||||
$publicAliases[(string) $alias][] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
$emptyAutowireAttributes = class_exists(Autowire::class) ? null : [];
|
||||
|
||||
foreach ($container->findTaggedServiceIds('controller.service_arguments', true) as $id => $tags) {
|
||||
$def = $container->getDefinition($id);
|
||||
$def->setPublic(true);
|
||||
$class = $def->getClass();
|
||||
$autowire = $def->isAutowired();
|
||||
$bindings = $def->getBindings();
|
||||
|
||||
// resolve service class, taking parent definitions into account
|
||||
while ($def instanceof ChildDefinition) {
|
||||
$def = $container->findDefinition($def->getParent());
|
||||
$class = $class ?: $def->getClass();
|
||||
$bindings += $def->getBindings();
|
||||
}
|
||||
$class = $parameterBag->resolveValue($class);
|
||||
|
||||
if (!$r = $container->getReflectionClass($class)) {
|
||||
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
|
||||
}
|
||||
|
||||
$controllerClasses[] = $class;
|
||||
|
||||
// get regular public methods
|
||||
$methods = [];
|
||||
$arguments = [];
|
||||
foreach ($r->getMethods(\ReflectionMethod::IS_PUBLIC) as $r) {
|
||||
if ('setContainer' === $r->name) {
|
||||
continue;
|
||||
}
|
||||
if (!$r->isConstructor() && !$r->isDestructor() && !$r->isAbstract()) {
|
||||
$methods[strtolower($r->name)] = [$r, $r->getParameters()];
|
||||
}
|
||||
}
|
||||
|
||||
// validate and collect explicit per-actions and per-arguments service references
|
||||
foreach ($tags as $attributes) {
|
||||
if (!isset($attributes['action']) && !isset($attributes['argument']) && !isset($attributes['id'])) {
|
||||
$autowire = true;
|
||||
continue;
|
||||
}
|
||||
foreach (['action', 'argument', 'id'] as $k) {
|
||||
if (!isset($attributes[$k][0])) {
|
||||
throw new InvalidArgumentException(sprintf('Missing "%s" attribute on tag "controller.service_arguments" %s for service "%s".', $k, json_encode($attributes, \JSON_UNESCAPED_UNICODE), $id));
|
||||
}
|
||||
}
|
||||
if (!isset($methods[$action = strtolower($attributes['action'])])) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid "action" attribute on tag "controller.service_arguments" for service "%s": no public "%s()" method found on class "%s".', $id, $attributes['action'], $class));
|
||||
}
|
||||
[$r, $parameters] = $methods[$action];
|
||||
$found = false;
|
||||
|
||||
foreach ($parameters as $p) {
|
||||
if ($attributes['argument'] === $p->name) {
|
||||
if (!isset($arguments[$r->name][$p->name])) {
|
||||
$arguments[$r->name][$p->name] = $attributes['id'];
|
||||
}
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$found) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid "controller.service_arguments" tag for service "%s": method "%s()" has no "%s" argument on class "%s".', $id, $r->name, $attributes['argument'], $class));
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($methods as [$r, $parameters]) {
|
||||
/** @var \ReflectionMethod $r */
|
||||
|
||||
// create a per-method map of argument-names to service/type-references
|
||||
$args = [];
|
||||
foreach ($parameters as $p) {
|
||||
/** @var \ReflectionParameter $p */
|
||||
$type = preg_replace('/(^|[(|&])\\\\/', '\1', $target = ltrim(ProxyHelper::exportType($p) ?? '', '?'));
|
||||
$invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
|
||||
$autowireAttributes = $autowire ? $emptyAutowireAttributes : [];
|
||||
$parsedName = $p->name;
|
||||
$k = null;
|
||||
|
||||
if (isset($arguments[$r->name][$p->name])) {
|
||||
$target = $arguments[$r->name][$p->name];
|
||||
if ('?' !== $target[0]) {
|
||||
$invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE;
|
||||
} elseif ('' === $target = (string) substr($target, 1)) {
|
||||
throw new InvalidArgumentException(sprintf('A "controller.service_arguments" tag must have non-empty "id" attributes for service "%s".', $id));
|
||||
} elseif ($p->allowsNull() && !$p->isOptional()) {
|
||||
$invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE;
|
||||
}
|
||||
} elseif (isset($bindings[$bindingName = $type.' $'.$name = Target::parseName($p, $k, $parsedName)])
|
||||
|| isset($bindings[$bindingName = $type.' $'.$parsedName])
|
||||
|| isset($bindings[$bindingName = '$'.$name])
|
||||
|| isset($bindings[$bindingName = $type])
|
||||
) {
|
||||
$binding = $bindings[$bindingName];
|
||||
|
||||
[$bindingValue, $bindingId, , $bindingType, $bindingFile] = $binding->getValues();
|
||||
$binding->setValues([$bindingValue, $bindingId, true, $bindingType, $bindingFile]);
|
||||
|
||||
$args[$p->name] = $bindingValue;
|
||||
|
||||
continue;
|
||||
} elseif (!$autowire || (!($autowireAttributes ??= $p->getAttributes(Autowire::class, \ReflectionAttribute::IS_INSTANCEOF)) && (!$type || '\\' !== $target[0]))) {
|
||||
continue;
|
||||
} elseif (is_subclass_of($type, \UnitEnum::class)) {
|
||||
// do not attempt to register enum typed arguments if not already present in bindings
|
||||
continue;
|
||||
} elseif (!$p->allowsNull()) {
|
||||
$invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE;
|
||||
}
|
||||
|
||||
if (Request::class === $type || SessionInterface::class === $type || Response::class === $type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($autowireAttributes) {
|
||||
$attribute = $autowireAttributes[0]->newInstance();
|
||||
$value = $parameterBag->resolveValue($attribute->value);
|
||||
|
||||
if ($attribute instanceof AutowireCallable) {
|
||||
$value = $attribute->buildDefinition($value, $type, $p);
|
||||
}
|
||||
|
||||
if ($value instanceof Reference) {
|
||||
$args[$p->name] = $type ? new TypedReference($value, $type, $invalidBehavior, $p->name) : new Reference($value, $invalidBehavior);
|
||||
} else {
|
||||
$args[$p->name] = new Reference('.value.'.$container->hash($value));
|
||||
$container->register((string) $args[$p->name], 'mixed')
|
||||
->setFactory('current')
|
||||
->addArgument([$value]);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($type && !$p->isOptional() && !$p->allowsNull() && !class_exists($type) && !interface_exists($type, false)) {
|
||||
$message = sprintf('Cannot determine controller argument for "%s::%s()": the $%s argument is type-hinted with the non-existent class or interface: "%s".', $class, $r->name, $p->name, $type);
|
||||
|
||||
// see if the type-hint lives in the same namespace as the controller
|
||||
if (0 === strncmp($type, $class, strrpos($class, '\\'))) {
|
||||
$message .= ' Did you forget to add a use statement?';
|
||||
}
|
||||
|
||||
$container->register($erroredId = '.errored.'.$container->hash($message), $type)
|
||||
->addError($message);
|
||||
|
||||
$args[$p->name] = new Reference($erroredId, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE);
|
||||
} else {
|
||||
$target = preg_replace('/(^|[(|&])\\\\/', '\1', $target);
|
||||
$args[$p->name] = $type ? new TypedReference($target, $type, $invalidBehavior, Target::parseName($p)) : new Reference($target, $invalidBehavior);
|
||||
}
|
||||
}
|
||||
// register the maps as a per-method service-locators
|
||||
if ($args) {
|
||||
$controllers[$id.'::'.$r->name] = ServiceLocatorTagPass::register($container, $args);
|
||||
|
||||
foreach ($publicAliases[$id] ?? [] as $alias) {
|
||||
$controllers[$alias.'::'.$r->name] = clone $controllers[$id.'::'.$r->name];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$controllerLocatorRef = ServiceLocatorTagPass::register($container, $controllers);
|
||||
|
||||
if ($container->hasDefinition('argument_resolver.service')) {
|
||||
$container->getDefinition('argument_resolver.service')
|
||||
->replaceArgument(0, $controllerLocatorRef);
|
||||
}
|
||||
|
||||
if ($container->hasDefinition('argument_resolver.not_tagged_controller')) {
|
||||
$container->getDefinition('argument_resolver.not_tagged_controller')
|
||||
->replaceArgument(0, $controllerLocatorRef);
|
||||
}
|
||||
|
||||
$container->setAlias('argument_resolver.controller_locator', (string) $controllerLocatorRef);
|
||||
|
||||
if ($container->hasDefinition('controller_resolver')) {
|
||||
$container->getDefinition('controller_resolver')
|
||||
->addMethodCall('allowControllers', [array_unique($controllerClasses)]);
|
||||
}
|
||||
}
|
||||
}
|
52
vendor/symfony/http-kernel/DependencyInjection/RegisterLocaleAwareServicesPass.php
vendored
Normal file
52
vendor/symfony/http-kernel/DependencyInjection/RegisterLocaleAwareServicesPass.php
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Register all services that have the "kernel.locale_aware" tag into the listener.
|
||||
*
|
||||
* @author Pierre Bobiet <pierrebobiet@gmail.com>
|
||||
*/
|
||||
class RegisterLocaleAwareServicesPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition('locale_aware_listener')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$services = [];
|
||||
|
||||
foreach ($container->findTaggedServiceIds('kernel.locale_aware') as $id => $tags) {
|
||||
$services[] = new Reference($id);
|
||||
}
|
||||
|
||||
if (!$services) {
|
||||
$container->removeDefinition('locale_aware_listener');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$container
|
||||
->getDefinition('locale_aware_listener')
|
||||
->setArgument(0, new IteratorArgument($services))
|
||||
;
|
||||
}
|
||||
}
|
71
vendor/symfony/http-kernel/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.php
vendored
Normal file
71
vendor/symfony/http-kernel/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.php
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Removes empty service-locators registered for ServiceValueResolver.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class RemoveEmptyControllerArgumentLocatorsPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$controllerLocator = $container->findDefinition('argument_resolver.controller_locator');
|
||||
$controllers = $controllerLocator->getArgument(0);
|
||||
|
||||
foreach ($controllers as $controller => $argumentRef) {
|
||||
$argumentLocator = $container->getDefinition((string) $argumentRef->getValues()[0]);
|
||||
|
||||
if (!$argumentLocator->getArgument(0)) {
|
||||
// remove empty argument locators
|
||||
$reason = sprintf('Removing service-argument resolver for controller "%s": no corresponding services exist for the referenced types.', $controller);
|
||||
} else {
|
||||
// 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)) {
|
||||
$reason = sprintf('Removing method "%s" of service "%s" from controller candidates: the method is called at instantiation, thus cannot be an action.', $action, $id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$reason) {
|
||||
// see Symfony\Component\HttpKernel\Controller\ContainerControllerResolver
|
||||
$controllers[$id.':'.$action] = $argumentRef;
|
||||
|
||||
if ('__invoke' === $action) {
|
||||
$controllers[$id] = $argumentRef;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
unset($controllers[$controller]);
|
||||
$container->log($this, $reason);
|
||||
}
|
||||
|
||||
$controllerLocator->replaceArgument(0, $controllers);
|
||||
}
|
||||
}
|
68
vendor/symfony/http-kernel/DependencyInjection/ResettableServicePass.php
vendored
Normal file
68
vendor/symfony/http-kernel/DependencyInjection/ResettableServicePass.php
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* @author Alexander M. Turek <me@derrabus.de>
|
||||
*/
|
||||
class ResettableServicePass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->has('services_resetter')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$services = $methods = [];
|
||||
|
||||
foreach ($container->findTaggedServiceIds('kernel.reset', true) as $id => $tags) {
|
||||
$services[$id] = new Reference($id, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE);
|
||||
|
||||
foreach ($tags as $attributes) {
|
||||
if (!isset($attributes['method'])) {
|
||||
throw new RuntimeException(sprintf('Tag "kernel.reset" requires the "method" attribute to be set on service "%s".', $id));
|
||||
}
|
||||
|
||||
if (!isset($methods[$id])) {
|
||||
$methods[$id] = [];
|
||||
}
|
||||
|
||||
if ('ignore' === ($attributes['on_invalid'] ?? null)) {
|
||||
$attributes['method'] = '?'.$attributes['method'];
|
||||
}
|
||||
|
||||
$methods[$id][] = $attributes['method'];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$services) {
|
||||
$container->removeAlias('services_resetter');
|
||||
$container->removeDefinition('services_resetter');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$container->findDefinition('services_resetter')
|
||||
->setArgument(0, new IteratorArgument($services))
|
||||
->setArgument(1, $methods);
|
||||
}
|
||||
}
|
61
vendor/symfony/http-kernel/DependencyInjection/ServicesResetter.php
vendored
Normal file
61
vendor/symfony/http-kernel/DependencyInjection/ServicesResetter.php
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DependencyInjection;
|
||||
|
||||
use ProxyManager\Proxy\LazyLoadingInterface;
|
||||
use Symfony\Component\VarExporter\LazyObjectInterface;
|
||||
use Symfony\Contracts\Service\ResetInterface;
|
||||
|
||||
/**
|
||||
* Resets provided services.
|
||||
*
|
||||
* @author Alexander M. Turek <me@derrabus.de>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ServicesResetter implements ResetInterface
|
||||
{
|
||||
private \Traversable $resettableServices;
|
||||
private array $resetMethods;
|
||||
|
||||
/**
|
||||
* @param \Traversable<string, object> $resettableServices
|
||||
* @param array<string, string|string[]> $resetMethods
|
||||
*/
|
||||
public function __construct(\Traversable $resettableServices, array $resetMethods)
|
||||
{
|
||||
$this->resettableServices = $resettableServices;
|
||||
$this->resetMethods = $resetMethods;
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
foreach ($this->resettableServices as $id => $service) {
|
||||
if ($service instanceof LazyObjectInterface && !$service->isLazyObjectInitialized(true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($service instanceof LazyLoadingInterface && !$service->isProxyInitialized()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ((array) $this->resetMethods[$id] as $resetMethod) {
|
||||
if ('?' === $resetMethod[0] && !method_exists($service, $resetMethod = substr($resetMethod, 1))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$service->$resetMethod();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
109
vendor/symfony/http-kernel/Event/ControllerArgumentsEvent.php
vendored
Normal file
109
vendor/symfony/http-kernel/Event/ControllerArgumentsEvent.php
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Allows filtering of controller arguments.
|
||||
*
|
||||
* You can call getController() to retrieve the controller and getArguments
|
||||
* to retrieve the current arguments. With setArguments() you can replace
|
||||
* arguments that are used to call the controller.
|
||||
*
|
||||
* Arguments set in the event must be compatible with the signature of the
|
||||
* controller.
|
||||
*
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
*/
|
||||
final class ControllerArgumentsEvent extends KernelEvent
|
||||
{
|
||||
private ControllerEvent $controllerEvent;
|
||||
private array $arguments;
|
||||
private array $namedArguments;
|
||||
|
||||
public function __construct(HttpKernelInterface $kernel, callable|ControllerEvent $controller, array $arguments, Request $request, ?int $requestType)
|
||||
{
|
||||
parent::__construct($kernel, $request, $requestType);
|
||||
|
||||
if (!$controller instanceof ControllerEvent) {
|
||||
$controller = new ControllerEvent($kernel, $controller, $request, $requestType);
|
||||
}
|
||||
|
||||
$this->controllerEvent = $controller;
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
|
||||
public function getController(): callable
|
||||
{
|
||||
return $this->controllerEvent->getController();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<class-string, list<object>>|null $attributes
|
||||
*/
|
||||
public function setController(callable $controller, ?array $attributes = null): void
|
||||
{
|
||||
$this->controllerEvent->setController($controller, $attributes);
|
||||
unset($this->namedArguments);
|
||||
}
|
||||
|
||||
public function getArguments(): array
|
||||
{
|
||||
return $this->arguments;
|
||||
}
|
||||
|
||||
public function setArguments(array $arguments): void
|
||||
{
|
||||
$this->arguments = $arguments;
|
||||
unset($this->namedArguments);
|
||||
}
|
||||
|
||||
public function getNamedArguments(): array
|
||||
{
|
||||
if (isset($this->namedArguments)) {
|
||||
return $this->namedArguments;
|
||||
}
|
||||
|
||||
$namedArguments = [];
|
||||
$arguments = $this->arguments;
|
||||
|
||||
foreach ($this->controllerEvent->getControllerReflector()->getParameters() as $i => $param) {
|
||||
if ($param->isVariadic()) {
|
||||
$namedArguments[$param->name] = \array_slice($arguments, $i);
|
||||
break;
|
||||
}
|
||||
if (\array_key_exists($i, $arguments)) {
|
||||
$namedArguments[$param->name] = $arguments[$i];
|
||||
} elseif ($param->isDefaultvalueAvailable()) {
|
||||
$namedArguments[$param->name] = $param->getDefaultValue();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->namedArguments = $namedArguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T of class-string|null
|
||||
*
|
||||
* @param T $className
|
||||
*
|
||||
* @return array<class-string, list<object>>|list<object>
|
||||
*
|
||||
* @psalm-return (T is null ? array<class-string, list<object>> : list<object>)
|
||||
*/
|
||||
public function getAttributes(?string $className = null): array
|
||||
{
|
||||
return $this->controllerEvent->getAttributes($className);
|
||||
}
|
||||
}
|
113
vendor/symfony/http-kernel/Event/ControllerEvent.php
vendored
Normal file
113
vendor/symfony/http-kernel/Event/ControllerEvent.php
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Allows filtering of a controller callable.
|
||||
*
|
||||
* You can call getController() to retrieve the current controller. With
|
||||
* setController() you can set a new controller that is used in the processing
|
||||
* of the request.
|
||||
*
|
||||
* Controllers should be callables.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
final class ControllerEvent extends KernelEvent
|
||||
{
|
||||
private string|array|object $controller;
|
||||
private \ReflectionFunctionAbstract $controllerReflector;
|
||||
private array $attributes;
|
||||
|
||||
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 getControllerReflector(): \ReflectionFunctionAbstract
|
||||
{
|
||||
return $this->controllerReflector;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<class-string, list<object>>|null $attributes
|
||||
*/
|
||||
public function setController(callable $controller, ?array $attributes = null): void
|
||||
{
|
||||
if (null !== $attributes) {
|
||||
$this->attributes = $attributes;
|
||||
}
|
||||
|
||||
if (isset($this->controller) && ($controller instanceof \Closure ? $controller == $this->controller : $controller === $this->controller)) {
|
||||
$this->controller = $controller;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (null === $attributes) {
|
||||
unset($this->attributes);
|
||||
}
|
||||
|
||||
if (\is_array($controller) && method_exists(...$controller)) {
|
||||
$this->controllerReflector = new \ReflectionMethod(...$controller);
|
||||
} elseif (\is_string($controller) && str_contains($controller, '::')) {
|
||||
$this->controllerReflector = new \ReflectionMethod(...explode('::', $controller, 2));
|
||||
} else {
|
||||
$this->controllerReflector = new \ReflectionFunction($controller(...));
|
||||
}
|
||||
|
||||
$this->controller = $controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T of class-string|null
|
||||
*
|
||||
* @param T $className
|
||||
*
|
||||
* @return array<class-string, list<object>>|list<object>
|
||||
*
|
||||
* @psalm-return (T is null ? array<class-string, list<object>> : list<object>)
|
||||
*/
|
||||
public function getAttributes(?string $className = null): array
|
||||
{
|
||||
if (isset($this->attributes)) {
|
||||
return null === $className ? $this->attributes : $this->attributes[$className] ?? [];
|
||||
}
|
||||
|
||||
if (\is_array($this->controller) && method_exists(...$this->controller)) {
|
||||
$class = new \ReflectionClass($this->controller[0]);
|
||||
} elseif (\is_string($this->controller) && false !== $i = strpos($this->controller, '::')) {
|
||||
$class = new \ReflectionClass(substr($this->controller, 0, $i));
|
||||
} else {
|
||||
$class = str_contains($this->controllerReflector->name, '{closure}') ? null : (\PHP_VERSION_ID >= 80111 ? $this->controllerReflector->getClosureCalledClass() : $this->controllerReflector->getClosureScopeClass());
|
||||
}
|
||||
$this->attributes = [];
|
||||
|
||||
foreach (array_merge($class?->getAttributes() ?? [], $this->controllerReflector->getAttributes()) as $attribute) {
|
||||
if (class_exists($attribute->getName())) {
|
||||
$this->attributes[$attribute->getName()][] = $attribute->newInstance();
|
||||
}
|
||||
}
|
||||
|
||||
return null === $className ? $this->attributes : $this->attributes[$className] ?? [];
|
||||
}
|
||||
}
|
72
vendor/symfony/http-kernel/Event/ExceptionEvent.php
vendored
Normal file
72
vendor/symfony/http-kernel/Event/ExceptionEvent.php
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Allows to create a response for a thrown exception.
|
||||
*
|
||||
* Call setResponse() to set the response that will be returned for the
|
||||
* current request. The propagation of this event is stopped as soon as a
|
||||
* response is set.
|
||||
*
|
||||
* You can also call setThrowable() to replace the thrown exception. This
|
||||
* exception will be thrown if no response is set during processing of this
|
||||
* event.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
final class ExceptionEvent extends RequestEvent
|
||||
{
|
||||
private \Throwable $throwable;
|
||||
private bool $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;
|
||||
}
|
||||
}
|
21
vendor/symfony/http-kernel/Event/FinishRequestEvent.php
vendored
Normal file
21
vendor/symfony/http-kernel/Event/FinishRequestEvent.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Triggered whenever a request is fully processed.
|
||||
*
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
final class FinishRequestEvent extends KernelEvent
|
||||
{
|
||||
}
|
74
vendor/symfony/http-kernel/Event/KernelEvent.php
vendored
Normal file
74
vendor/symfony/http-kernel/Event/KernelEvent.php
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
<?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;
|
||||
use Symfony\Contracts\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Base class for events thrown in the HttpKernel component.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class KernelEvent extends Event
|
||||
{
|
||||
private HttpKernelInterface $kernel;
|
||||
private Request $request;
|
||||
private ?int $requestType;
|
||||
|
||||
/**
|
||||
* @param int $requestType The request type the kernel is currently processing; one of
|
||||
* HttpKernelInterface::MAIN_REQUEST or HttpKernelInterface::SUB_REQUEST
|
||||
*/
|
||||
public function __construct(HttpKernelInterface $kernel, Request $request, ?int $requestType)
|
||||
{
|
||||
$this->kernel = $kernel;
|
||||
$this->request = $request;
|
||||
$this->requestType = $requestType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the kernel in which this event was thrown.
|
||||
*/
|
||||
public function getKernel(): HttpKernelInterface
|
||||
{
|
||||
return $this->kernel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request the kernel is currently processing.
|
||||
*/
|
||||
public function getRequest(): Request
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request type the kernel is currently processing.
|
||||
*
|
||||
* @return int One of HttpKernelInterface::MAIN_REQUEST and
|
||||
* HttpKernelInterface::SUB_REQUEST
|
||||
*/
|
||||
public function getRequestType(): int
|
||||
{
|
||||
return $this->requestType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this is the main request.
|
||||
*/
|
||||
public function isMainRequest(): bool
|
||||
{
|
||||
return HttpKernelInterface::MAIN_REQUEST === $this->requestType;
|
||||
}
|
||||
}
|
56
vendor/symfony/http-kernel/Event/RequestEvent.php
vendored
Normal file
56
vendor/symfony/http-kernel/Event/RequestEvent.php
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Allows to create a response for a request.
|
||||
*
|
||||
* Call setResponse() to set the response that will be returned for the
|
||||
* current request. The propagation of this event is stopped as soon as a
|
||||
* response is set.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class RequestEvent extends KernelEvent
|
||||
{
|
||||
private ?Response $response = null;
|
||||
|
||||
/**
|
||||
* Returns the response object.
|
||||
*/
|
||||
public function getResponse(): ?Response
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a response and stops event propagation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setResponse(Response $response)
|
||||
{
|
||||
$this->response = $response;
|
||||
|
||||
$this->stopPropagation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a response was set.
|
||||
*/
|
||||
public function hasResponse(): bool
|
||||
{
|
||||
return null !== $this->response;
|
||||
}
|
||||
}
|
47
vendor/symfony/http-kernel/Event/ResponseEvent.php
vendored
Normal file
47
vendor/symfony/http-kernel/Event/ResponseEvent.php
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Allows to filter a Response object.
|
||||
*
|
||||
* You can call getResponse() to retrieve the current response. With
|
||||
* setResponse() you can set a new response that will be returned to the
|
||||
* browser.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
final class ResponseEvent extends KernelEvent
|
||||
{
|
||||
private Response $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;
|
||||
}
|
||||
}
|
41
vendor/symfony/http-kernel/Event/TerminateEvent.php
vendored
Normal file
41
vendor/symfony/http-kernel/Event/TerminateEvent.php
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Event;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
|
||||
/**
|
||||
* Allows to execute logic after a response was sent.
|
||||
*
|
||||
* Since it's only triggered on main requests, the `getRequestType()` method
|
||||
* will always return the value of `HttpKernelInterface::MAIN_REQUEST`.
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
final class TerminateEvent extends KernelEvent
|
||||
{
|
||||
private Response $response;
|
||||
|
||||
public function __construct(HttpKernelInterface $kernel, Request $request, Response $response)
|
||||
{
|
||||
parent::__construct($kernel, $request, HttpKernelInterface::MAIN_REQUEST);
|
||||
|
||||
$this->response = $response;
|
||||
}
|
||||
|
||||
public function getResponse(): Response
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
}
|
48
vendor/symfony/http-kernel/Event/ViewEvent.php
vendored
Normal file
48
vendor/symfony/http-kernel/Event/ViewEvent.php
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Allows to create a response for the return value of a controller.
|
||||
*
|
||||
* Call setResponse() to set the response that will be returned for the
|
||||
* current request. The propagation of this event is stopped as soon as a
|
||||
* response is set.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
final class ViewEvent extends RequestEvent
|
||||
{
|
||||
public readonly ?ControllerArgumentsEvent $controllerArgumentsEvent;
|
||||
private mixed $controllerResult;
|
||||
|
||||
public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, mixed $controllerResult, ?ControllerArgumentsEvent $controllerArgumentsEvent = null)
|
||||
{
|
||||
parent::__construct($kernel, $request, $requestType);
|
||||
|
||||
$this->controllerResult = $controllerResult;
|
||||
$this->controllerArgumentsEvent = $controllerArgumentsEvent;
|
||||
}
|
||||
|
||||
public function getControllerResult(): mixed
|
||||
{
|
||||
return $this->controllerResult;
|
||||
}
|
||||
|
||||
public function setControllerResult(mixed $controllerResult): void
|
||||
{
|
||||
$this->controllerResult = $controllerResult;
|
||||
}
|
||||
}
|
324
vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php
vendored
Normal file
324
vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php
vendored
Normal file
@ -0,0 +1,324 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\EventListener;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\Cookie;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionUtils;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\HttpKernel\Event\ResponseEvent;
|
||||
use Symfony\Component\HttpKernel\Exception\UnexpectedSessionUsageException;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Contracts\Service\ResetInterface;
|
||||
|
||||
/**
|
||||
* Sets the session onto the request on the "kernel.request" event and saves
|
||||
* it on the "kernel.response" event.
|
||||
*
|
||||
* In addition, if the session has been started it overrides the Cache-Control
|
||||
* header in such a way that all caching is disabled in that case.
|
||||
* If you have a scenario where caching responses with session information in
|
||||
* them makes sense, you can disable this behaviour by setting the header
|
||||
* AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER on the response.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
* @author Tobias Schultze <http://tobion.de>
|
||||
*/
|
||||
abstract class AbstractSessionListener implements EventSubscriberInterface, ResetInterface
|
||||
{
|
||||
public const NO_AUTO_CACHE_CONTROL_HEADER = 'Symfony-Session-NoAutoCacheControl';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
protected ?ContainerInterface $container;
|
||||
|
||||
private bool $debug;
|
||||
|
||||
/**
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
private array $sessionOptions;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function __construct(?ContainerInterface $container = null, bool $debug = false, array $sessionOptions = [])
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->debug = $debug;
|
||||
$this->sessionOptions = $sessionOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function onKernelRequest(RequestEvent $event): void
|
||||
{
|
||||
if (!$event->isMainRequest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$request = $event->getRequest();
|
||||
if (!$request->hasSession()) {
|
||||
$request->setSessionFactory(function () use ($request) {
|
||||
// Prevent calling `$this->getSession()` twice in case the Request (and the below factory) is cloned
|
||||
static $sess;
|
||||
|
||||
if (!$sess) {
|
||||
$sess = $this->getSession();
|
||||
$request->setSession($sess);
|
||||
|
||||
/*
|
||||
* For supporting sessions in php runtime with runners like roadrunner or swoole, the session
|
||||
* cookie needs to be read from the cookie bag and set on the session storage.
|
||||
*
|
||||
* Do not set it when a native php session is active.
|
||||
*/
|
||||
if ($sess && !$sess->isStarted() && \PHP_SESSION_ACTIVE !== session_status()) {
|
||||
$sessionId = $sess->getId() ?: $request->cookies->get($sess->getName(), '');
|
||||
$sess->setId($sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
return $sess;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function onKernelResponse(ResponseEvent $event): void
|
||||
{
|
||||
if (!$event->isMainRequest() || (!$this->container->has('initialized_session') && !$event->getRequest()->hasSession())) {
|
||||
return;
|
||||
}
|
||||
|
||||
$response = $event->getResponse();
|
||||
$autoCacheControl = !$response->headers->has(self::NO_AUTO_CACHE_CONTROL_HEADER);
|
||||
// Always remove the internal header if present
|
||||
$response->headers->remove(self::NO_AUTO_CACHE_CONTROL_HEADER);
|
||||
if (!$event->getRequest()->hasSession(true)) {
|
||||
return;
|
||||
}
|
||||
$session = $event->getRequest()->getSession();
|
||||
|
||||
if ($session->isStarted()) {
|
||||
/*
|
||||
* Saves the session, in case it is still open, before sending the response/headers.
|
||||
*
|
||||
* This ensures several things in case the developer did not save the session explicitly:
|
||||
*
|
||||
* * If a session save handler without locking is used, it ensures the data is available
|
||||
* on the next request, e.g. after a redirect. PHPs auto-save at script end via
|
||||
* session_register_shutdown is executed after fastcgi_finish_request. So in this case
|
||||
* the data could be missing the next request because it might not be saved the moment
|
||||
* the new request is processed.
|
||||
* * A locking save handler (e.g. the native 'files') circumvents concurrency problems like
|
||||
* the one above. But by saving the session before long-running things in the terminate event,
|
||||
* we ensure the session is not blocked longer than needed.
|
||||
* * When regenerating the session ID no locking is involved in PHPs session design. See
|
||||
* https://bugs.php.net/61470 for a discussion. So in this case, the session must
|
||||
* be saved anyway before sending the headers with the new session ID. Otherwise session
|
||||
* data could get lost again for concurrent requests with the new ID. One result could be
|
||||
* that you get logged out after just logging in.
|
||||
*
|
||||
* This listener should be executed as one of the last listeners, so that previous listeners
|
||||
* can still operate on the open session. This prevents the overhead of restarting it.
|
||||
* Listeners after closing the session can still work with the session as usual because
|
||||
* Symfonys session implementation starts the session on demand. So writing to it after
|
||||
* it is saved will just restart it.
|
||||
*/
|
||||
$session->save();
|
||||
|
||||
/*
|
||||
* For supporting sessions in php runtime with runners like roadrunner or swoole the session
|
||||
* cookie need to be written on the response object and should not be written by PHP itself.
|
||||
*/
|
||||
$sessionName = $session->getName();
|
||||
$sessionId = $session->getId();
|
||||
$sessionOptions = $this->getSessionOptions($this->sessionOptions);
|
||||
$sessionCookiePath = $sessionOptions['cookie_path'] ?? '/';
|
||||
$sessionCookieDomain = $sessionOptions['cookie_domain'] ?? null;
|
||||
$sessionCookieSecure = $sessionOptions['cookie_secure'] ?? false;
|
||||
$sessionCookieHttpOnly = $sessionOptions['cookie_httponly'] ?? true;
|
||||
$sessionCookieSameSite = $sessionOptions['cookie_samesite'] ?? Cookie::SAMESITE_LAX;
|
||||
$sessionUseCookies = $sessionOptions['use_cookies'] ?? true;
|
||||
|
||||
SessionUtils::popSessionCookie($sessionName, $sessionId);
|
||||
|
||||
if ($sessionUseCookies) {
|
||||
$request = $event->getRequest();
|
||||
$requestSessionCookieId = $request->cookies->get($sessionName);
|
||||
|
||||
$isSessionEmpty = ($session instanceof Session ? $session->isEmpty() : !$session->all()) && empty($_SESSION); // checking $_SESSION to keep compatibility with native sessions
|
||||
if ($requestSessionCookieId && $isSessionEmpty) {
|
||||
// PHP internally sets the session cookie value to "deleted" when setcookie() is called with empty string $value argument
|
||||
// which happens in \Symfony\Component\HttpFoundation\Session\Storage\Handler\AbstractSessionHandler::destroy
|
||||
// when the session gets invalidated (for example on logout) so we must handle this case here too
|
||||
// otherwise we would send two Set-Cookie headers back with the response
|
||||
SessionUtils::popSessionCookie($sessionName, 'deleted');
|
||||
$response->headers->clearCookie(
|
||||
$sessionName,
|
||||
$sessionCookiePath,
|
||||
$sessionCookieDomain,
|
||||
$sessionCookieSecure,
|
||||
$sessionCookieHttpOnly,
|
||||
$sessionCookieSameSite
|
||||
);
|
||||
} elseif ($sessionId !== $requestSessionCookieId && !$isSessionEmpty) {
|
||||
$expire = 0;
|
||||
$lifetime = $sessionOptions['cookie_lifetime'] ?? null;
|
||||
if ($lifetime) {
|
||||
$expire = time() + $lifetime;
|
||||
}
|
||||
|
||||
$response->headers->setCookie(
|
||||
Cookie::create(
|
||||
$sessionName,
|
||||
$sessionId,
|
||||
$expire,
|
||||
$sessionCookiePath,
|
||||
$sessionCookieDomain,
|
||||
$sessionCookieSecure,
|
||||
$sessionCookieHttpOnly,
|
||||
false,
|
||||
$sessionCookieSameSite
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($session instanceof Session ? 0 === $session->getUsageIndex() : !$session->isStarted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($autoCacheControl) {
|
||||
$maxAge = $response->headers->hasCacheControlDirective('public') ? 0 : (int) $response->getMaxAge();
|
||||
$response
|
||||
->setExpires(new \DateTimeImmutable('+'.$maxAge.' seconds'))
|
||||
->setPrivate()
|
||||
->setMaxAge($maxAge)
|
||||
->headers->addCacheControlDirective('must-revalidate');
|
||||
}
|
||||
|
||||
if (!$event->getRequest()->attributes->get('_stateless', false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->debug) {
|
||||
throw new UnexpectedSessionUsageException('Session was used while the request was declared stateless.');
|
||||
}
|
||||
|
||||
if ($this->container->has('logger')) {
|
||||
$this->container->get('logger')->warning('Session was used while the request was declared stateless.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function onSessionUsage(): void
|
||||
{
|
||||
if (!$this->debug) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->container?->has('session_collector')) {
|
||||
$this->container->get('session_collector')();
|
||||
}
|
||||
|
||||
if (!$requestStack = $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 = $requestStack->getCurrentRequest()->getSession()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($session->isStarted()) {
|
||||
$session->save();
|
||||
}
|
||||
|
||||
throw new UnexpectedSessionUsageException('Session was used while the request was declared stateless.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
KernelEvents::REQUEST => ['onKernelRequest', 128],
|
||||
// low priority to come after regular response listeners
|
||||
KernelEvents::RESPONSE => ['onKernelResponse', -1000],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function reset(): void
|
||||
{
|
||||
if (\PHP_SESSION_ACTIVE === session_status()) {
|
||||
session_abort();
|
||||
}
|
||||
|
||||
session_unset();
|
||||
$_SESSION = [];
|
||||
|
||||
if (!headers_sent()) { // session id can only be reset when no headers were so we check for headers_sent first
|
||||
session_id('');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the session object.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
abstract protected function getSession(): ?SessionInterface;
|
||||
|
||||
private function getSessionOptions(array $sessionOptions): array
|
||||
{
|
||||
$mergedSessionOptions = [];
|
||||
|
||||
foreach (session_get_cookie_params() as $key => $value) {
|
||||
$mergedSessionOptions['cookie_'.$key] = $value;
|
||||
}
|
||||
|
||||
foreach ($sessionOptions as $key => $value) {
|
||||
// do the same logic as in the NativeSessionStorage
|
||||
if ('cookie_secure' === $key && 'auto' === $value) {
|
||||
continue;
|
||||
}
|
||||
$mergedSessionOptions[$key] = $value;
|
||||
}
|
||||
|
||||
return $mergedSessionOptions;
|
||||
}
|
||||
}
|
49
vendor/symfony/http-kernel/EventListener/AddRequestFormatsListener.php
vendored
Normal file
49
vendor/symfony/http-kernel/EventListener/AddRequestFormatsListener.php
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\EventListener;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
|
||||
/**
|
||||
* Adds configured formats to each request.
|
||||
*
|
||||
* @author Gildas Quemener <gildas.quemener@gmail.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class AddRequestFormatsListener implements EventSubscriberInterface
|
||||
{
|
||||
private array $formats;
|
||||
|
||||
public function __construct(array $formats)
|
||||
{
|
||||
$this->formats = $formats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds request formats.
|
||||
*/
|
||||
public function onKernelRequest(RequestEvent $event): void
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
foreach ($this->formats as $format => $mimeTypes) {
|
||||
$request->setFormat($format, $mimeTypes);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [KernelEvents::REQUEST => ['onKernelRequest', 100]];
|
||||
}
|
||||
}
|
197
vendor/symfony/http-kernel/EventListener/CacheAttributeListener.php
vendored
Normal file
197
vendor/symfony/http-kernel/EventListener/CacheAttributeListener.php
vendored
Normal file
@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\EventListener;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Attribute\Cache;
|
||||
use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
|
||||
use Symfony\Component\HttpKernel\Event\ResponseEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
|
||||
/**
|
||||
* Handles HTTP cache headers configured via the Cache attribute.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class CacheAttributeListener implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @var \SplObjectStorage<Request, \DateTimeInterface>
|
||||
*/
|
||||
private \SplObjectStorage $lastModified;
|
||||
|
||||
/**
|
||||
* @var \SplObjectStorage<Request, string>
|
||||
*/
|
||||
private \SplObjectStorage $etags;
|
||||
|
||||
public function __construct(
|
||||
private ?ExpressionLanguage $expressionLanguage = null,
|
||||
) {
|
||||
$this->lastModified = new \SplObjectStorage();
|
||||
$this->etags = new \SplObjectStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles HTTP validation headers.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onKernelControllerArguments(ControllerArgumentsEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
if (!\is_array($attributes = $request->attributes->get('_cache') ?? $event->getAttributes()[Cache::class] ?? null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$request->attributes->set('_cache', $attributes);
|
||||
$response = null;
|
||||
$lastModified = null;
|
||||
$etag = null;
|
||||
|
||||
/** @var Cache[] $attributes */
|
||||
foreach ($attributes as $cache) {
|
||||
if (null !== $cache->lastModified) {
|
||||
$lastModified = $this->getExpressionLanguage()->evaluate($cache->lastModified, array_merge($request->attributes->all(), $event->getNamedArguments()));
|
||||
($response ??= new Response())->setLastModified($lastModified);
|
||||
}
|
||||
|
||||
if (null !== $cache->etag) {
|
||||
$etag = hash('sha256', $this->getExpressionLanguage()->evaluate($cache->etag, array_merge($request->attributes->all(), $event->getNamedArguments())));
|
||||
($response ??= new Response())->setEtag($etag);
|
||||
}
|
||||
}
|
||||
|
||||
if ($response?->isNotModified($request)) {
|
||||
$event->setController(static fn () => $response);
|
||||
$event->stopPropagation();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (null !== $etag) {
|
||||
$this->etags[$request] = $etag;
|
||||
}
|
||||
if (null !== $lastModified) {
|
||||
$this->lastModified[$request] = $lastModified;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the response to apply HTTP cache headers when needed.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onKernelResponse(ResponseEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
/** @var Cache[] $attributes */
|
||||
if (!\is_array($attributes = $request->attributes->get('_cache'))) {
|
||||
return;
|
||||
}
|
||||
$response = $event->getResponse();
|
||||
|
||||
// http://tools.ietf.org/html/draft-ietf-httpbis-p4-conditional-12#section-3.1
|
||||
if (!\in_array($response->getStatusCode(), [200, 203, 300, 301, 302, 304, 404, 410])) {
|
||||
unset($this->lastModified[$request]);
|
||||
unset($this->etags[$request]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($this->lastModified[$request]) && !$response->headers->has('Last-Modified')) {
|
||||
$response->setLastModified($this->lastModified[$request]);
|
||||
}
|
||||
|
||||
if (isset($this->etags[$request]) && !$response->headers->has('Etag')) {
|
||||
$response->setEtag($this->etags[$request]);
|
||||
}
|
||||
|
||||
unset($this->lastModified[$request]);
|
||||
unset($this->etags[$request]);
|
||||
$hasVary = $response->headers->has('Vary');
|
||||
|
||||
foreach (array_reverse($attributes) as $cache) {
|
||||
if (null !== $cache->smaxage && !$response->headers->hasCacheControlDirective('s-maxage')) {
|
||||
$response->setSharedMaxAge($this->toSeconds($cache->smaxage));
|
||||
}
|
||||
|
||||
if ($cache->mustRevalidate) {
|
||||
$response->headers->addCacheControlDirective('must-revalidate');
|
||||
}
|
||||
|
||||
if (null !== $cache->maxage && !$response->headers->hasCacheControlDirective('max-age')) {
|
||||
$response->setMaxAge($this->toSeconds($cache->maxage));
|
||||
}
|
||||
|
||||
if (null !== $cache->maxStale && !$response->headers->hasCacheControlDirective('max-stale')) {
|
||||
$response->headers->addCacheControlDirective('max-stale', $this->toSeconds($cache->maxStale));
|
||||
}
|
||||
|
||||
if (null !== $cache->staleWhileRevalidate && !$response->headers->hasCacheControlDirective('stale-while-revalidate')) {
|
||||
$response->headers->addCacheControlDirective('stale-while-revalidate', $this->toSeconds($cache->staleWhileRevalidate));
|
||||
}
|
||||
|
||||
if (null !== $cache->staleIfError && !$response->headers->hasCacheControlDirective('stale-if-error')) {
|
||||
$response->headers->addCacheControlDirective('stale-if-error', $this->toSeconds($cache->staleIfError));
|
||||
}
|
||||
|
||||
if (null !== $cache->expires && !$response->headers->has('Expires')) {
|
||||
$response->setExpires(new \DateTimeImmutable('@'.strtotime($cache->expires, time())));
|
||||
}
|
||||
|
||||
if (!$hasVary && $cache->vary) {
|
||||
$response->setVary($cache->vary, false);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($attributes as $cache) {
|
||||
if (true === $cache->public) {
|
||||
$response->setPublic();
|
||||
}
|
||||
|
||||
if (false === $cache->public) {
|
||||
$response->setPrivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
KernelEvents::CONTROLLER_ARGUMENTS => ['onKernelControllerArguments', 10],
|
||||
KernelEvents::RESPONSE => ['onKernelResponse', -10],
|
||||
];
|
||||
}
|
||||
|
||||
private function getExpressionLanguage(): ExpressionLanguage
|
||||
{
|
||||
return $this->expressionLanguage ??= class_exists(ExpressionLanguage::class)
|
||||
? new ExpressionLanguage()
|
||||
: throw new \LogicException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed. Try running "composer require symfony/expression-language".');
|
||||
}
|
||||
|
||||
private function toSeconds(int|string $time): int
|
||||
{
|
||||
if (!is_numeric($time)) {
|
||||
$now = time();
|
||||
$time = strtotime($time, $now) - $now;
|
||||
}
|
||||
|
||||
return $time;
|
||||
}
|
||||
}
|
121
vendor/symfony/http-kernel/EventListener/DebugHandlersListener.php
vendored
Normal file
121
vendor/symfony/http-kernel/EventListener/DebugHandlersListener.php
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
<?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\Console\ConsoleEvents;
|
||||
use Symfony\Component\Console\Event\ConsoleEvent;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\ErrorHandler\ErrorHandler;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Event\KernelEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
|
||||
/**
|
||||
* Sets an exception handler.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @final
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class DebugHandlersListener implements EventSubscriberInterface
|
||||
{
|
||||
private string|object|null $earlyHandler;
|
||||
private ?\Closure $exceptionHandler;
|
||||
private bool $webMode;
|
||||
private bool $firstCall = true;
|
||||
private bool $hasTerminatedWithException = false;
|
||||
|
||||
/**
|
||||
* @param bool $webMode
|
||||
* @param callable|null $exceptionHandler A handler that must support \Throwable instances that will be called on Exception
|
||||
*/
|
||||
public function __construct(?callable $exceptionHandler = null, bool|LoggerInterface|null $webMode = null)
|
||||
{
|
||||
if ($webMode instanceof LoggerInterface) {
|
||||
// BC with Symfony 5
|
||||
$webMode = null;
|
||||
}
|
||||
$handler = set_exception_handler('is_int');
|
||||
$this->earlyHandler = \is_array($handler) ? $handler[0] : null;
|
||||
restore_exception_handler();
|
||||
|
||||
$this->exceptionHandler = null === $exceptionHandler ? null : $exceptionHandler(...);
|
||||
$this->webMode = $webMode ?? !\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the error handler.
|
||||
*/
|
||||
public function configure(?object $event = null): void
|
||||
{
|
||||
if ($event instanceof ConsoleEvent && $this->webMode) {
|
||||
return;
|
||||
}
|
||||
if (!$event instanceof KernelEvent ? !$this->firstCall : !$event->isMainRequest()) {
|
||||
return;
|
||||
}
|
||||
$this->firstCall = $this->hasTerminatedWithException = false;
|
||||
|
||||
if (!$this->exceptionHandler) {
|
||||
if ($event instanceof KernelEvent) {
|
||||
if (method_exists($kernel = $event->getKernel(), 'terminateWithException')) {
|
||||
$request = $event->getRequest();
|
||||
$hasRun = &$this->hasTerminatedWithException;
|
||||
$this->exceptionHandler = static function (\Throwable $e) use ($kernel, $request, &$hasRun) {
|
||||
if ($hasRun) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$hasRun = true;
|
||||
$kernel->terminateWithException($e, $request);
|
||||
};
|
||||
}
|
||||
} elseif ($event instanceof ConsoleEvent && $app = $event->getCommand()->getApplication()) {
|
||||
$output = $event->getOutput();
|
||||
if ($output instanceof ConsoleOutputInterface) {
|
||||
$output = $output->getErrorOutput();
|
||||
}
|
||||
$this->exceptionHandler = static function (\Throwable $e) use ($app, $output) {
|
||||
$app->renderThrowable($e, $output);
|
||||
};
|
||||
}
|
||||
}
|
||||
if ($this->exceptionHandler) {
|
||||
$handler = set_exception_handler(static fn () => null);
|
||||
$handler = \is_array($handler) ? $handler[0] : null;
|
||||
restore_exception_handler();
|
||||
|
||||
if (!$handler instanceof ErrorHandler) {
|
||||
$handler = $this->earlyHandler;
|
||||
}
|
||||
|
||||
if ($handler instanceof ErrorHandler) {
|
||||
$handler->setExceptionHandler($this->exceptionHandler);
|
||||
}
|
||||
$this->exceptionHandler = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
$events = [KernelEvents::REQUEST => ['configure', 2048]];
|
||||
|
||||
if (\defined('Symfony\Component\Console\ConsoleEvents::COMMAND')) {
|
||||
$events[ConsoleEvents::COMMAND] = ['configure', 2048];
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
}
|
40
vendor/symfony/http-kernel/EventListener/DisallowRobotsIndexingListener.php
vendored
Normal file
40
vendor/symfony/http-kernel/EventListener/DisallowRobotsIndexingListener.php
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\EventListener;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Event\ResponseEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
|
||||
/**
|
||||
* Ensures that the application is not indexed by search engines.
|
||||
*
|
||||
* @author Gary PEGEOT <garypegeot@gmail.com>
|
||||
*/
|
||||
class DisallowRobotsIndexingListener implements EventSubscriberInterface
|
||||
{
|
||||
private const HEADER_NAME = 'X-Robots-Tag';
|
||||
|
||||
public function onResponse(ResponseEvent $event): void
|
||||
{
|
||||
if (!$event->getResponse()->headers->has(static::HEADER_NAME)) {
|
||||
$event->getResponse()->headers->set(static::HEADER_NAME, 'noindex');
|
||||
}
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
KernelEvents::RESPONSE => ['onResponse', -255],
|
||||
];
|
||||
}
|
||||
}
|
69
vendor/symfony/http-kernel/EventListener/DumpListener.php
vendored
Normal file
69
vendor/symfony/http-kernel/EventListener/DumpListener.php
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\EventListener;
|
||||
|
||||
use Symfony\Component\Console\ConsoleEvents;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\VarDumper\Cloner\ClonerInterface;
|
||||
use Symfony\Component\VarDumper\Dumper\DataDumperInterface;
|
||||
use Symfony\Component\VarDumper\Server\Connection;
|
||||
use Symfony\Component\VarDumper\VarDumper;
|
||||
|
||||
/**
|
||||
* Configures dump() handler.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class DumpListener implements EventSubscriberInterface
|
||||
{
|
||||
private ClonerInterface $cloner;
|
||||
private DataDumperInterface $dumper;
|
||||
private ?Connection $connection;
|
||||
|
||||
public function __construct(ClonerInterface $cloner, DataDumperInterface $dumper, ?Connection $connection = null)
|
||||
{
|
||||
$this->cloner = $cloner;
|
||||
$this->dumper = $dumper;
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function configure()
|
||||
{
|
||||
$cloner = $this->cloner;
|
||||
$dumper = $this->dumper;
|
||||
$connection = $this->connection;
|
||||
|
||||
VarDumper::setHandler(static function ($var, ?string $label = null) use ($cloner, $dumper, $connection) {
|
||||
$data = $cloner->cloneVar($var);
|
||||
if (null !== $label) {
|
||||
$data = $data->withContext(['label' => $label]);
|
||||
}
|
||||
|
||||
if (!$connection || !$connection->write($data)) {
|
||||
$dumper->dump($data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
if (!class_exists(ConsoleEvents::class)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Register early to have a working dump() as early as possible
|
||||
return [ConsoleEvents::COMMAND => ['configure', 1024]];
|
||||
}
|
||||
}
|
241
vendor/symfony/http-kernel/EventListener/ErrorListener.php
vendored
Normal file
241
vendor/symfony/http-kernel/EventListener/ErrorListener.php
vendored
Normal file
@ -0,0 +1,241 @@
|
||||
<?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 Psr\Log\LogLevel;
|
||||
use Symfony\Component\ErrorHandler\ErrorHandler;
|
||||
use Symfony\Component\ErrorHandler\Exception\FlattenException;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Attribute\WithHttpStatus;
|
||||
use Symfony\Component\HttpKernel\Attribute\WithLogLevel;
|
||||
use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
|
||||
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
|
||||
use Symfony\Component\HttpKernel\Event\ResponseEvent;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Component\HttpKernel\Log\DebugLoggerConfigurator;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class ErrorListener implements EventSubscriberInterface
|
||||
{
|
||||
protected $controller;
|
||||
protected $logger;
|
||||
protected $debug;
|
||||
/**
|
||||
* @var array<class-string, array{log_level: string|null, status_code: int<100,599>|null}>
|
||||
*/
|
||||
protected $exceptionsMapping;
|
||||
|
||||
/**
|
||||
* @param array<class-string, array{log_level: string|null, status_code: int<100,599>|null}> $exceptionsMapping
|
||||
*/
|
||||
public function __construct(string|object|array|null $controller, ?LoggerInterface $logger = null, bool $debug = false, array $exceptionsMapping = [])
|
||||
{
|
||||
$this->controller = $controller;
|
||||
$this->logger = $logger;
|
||||
$this->debug = $debug;
|
||||
$this->exceptionsMapping = $exceptionsMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function logKernelException(ExceptionEvent $event)
|
||||
{
|
||||
$throwable = $event->getThrowable();
|
||||
$logLevel = $this->resolveLogLevel($throwable);
|
||||
|
||||
foreach ($this->exceptionsMapping as $class => $config) {
|
||||
if (!$throwable instanceof $class || !$config['status_code']) {
|
||||
continue;
|
||||
}
|
||||
if (!$throwable instanceof HttpExceptionInterface || $throwable->getStatusCode() !== $config['status_code']) {
|
||||
$headers = $throwable instanceof HttpExceptionInterface ? $throwable->getHeaders() : [];
|
||||
$throwable = new HttpException($config['status_code'], $throwable->getMessage(), $throwable, $headers);
|
||||
$event->setThrowable($throwable);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// There's no specific status code defined in the configuration for this exception
|
||||
if (!$throwable instanceof HttpExceptionInterface) {
|
||||
$class = new \ReflectionClass($throwable);
|
||||
|
||||
do {
|
||||
if ($attributes = $class->getAttributes(WithHttpStatus::class, \ReflectionAttribute::IS_INSTANCEOF)) {
|
||||
/** @var WithHttpStatus $instance */
|
||||
$instance = $attributes[0]->newInstance();
|
||||
|
||||
$throwable = new HttpException($instance->statusCode, $throwable->getMessage(), $throwable, $instance->headers);
|
||||
$event->setThrowable($throwable);
|
||||
break;
|
||||
}
|
||||
} while ($class = $class->getParentClass());
|
||||
}
|
||||
|
||||
$e = FlattenException::createFromThrowable($throwable);
|
||||
|
||||
$this->logException($throwable, sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', $e->getClass(), $e->getMessage(), basename($e->getFile()), $e->getLine()), $logLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function onKernelException(ExceptionEvent $event)
|
||||
{
|
||||
if (null === $this->controller) {
|
||||
return;
|
||||
}
|
||||
|
||||
$throwable = $event->getThrowable();
|
||||
|
||||
if ($exceptionHandler = set_exception_handler(var_dump(...))) {
|
||||
restore_exception_handler();
|
||||
if (\is_array($exceptionHandler) && $exceptionHandler[0] instanceof ErrorHandler) {
|
||||
$throwable = $exceptionHandler[0]->enhanceError($event->getThrowable());
|
||||
}
|
||||
}
|
||||
|
||||
$request = $this->duplicateRequest($throwable, $event->getRequest());
|
||||
|
||||
try {
|
||||
$response = $event->getKernel()->handle($request, HttpKernelInterface::SUB_REQUEST, false);
|
||||
} catch (\Exception $e) {
|
||||
$f = FlattenException::createFromThrowable($e);
|
||||
|
||||
$this->logException($e, sprintf('Exception thrown when handling an exception (%s: %s at %s line %s)', $f->getClass(), $f->getMessage(), basename($e->getFile()), $e->getLine()));
|
||||
|
||||
$prev = $e;
|
||||
do {
|
||||
if ($throwable === $wrapper = $prev) {
|
||||
throw $e;
|
||||
}
|
||||
} while ($prev = $wrapper->getPrevious());
|
||||
|
||||
$prev = new \ReflectionProperty($wrapper instanceof \Exception ? \Exception::class : \Error::class, 'previous');
|
||||
$prev->setValue($wrapper, $throwable);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$event->setResponse($response);
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function onControllerArguments(ControllerArgumentsEvent $event)
|
||||
{
|
||||
$e = $event->getRequest()->attributes->get('exception');
|
||||
|
||||
if (!$e instanceof \Throwable || false === $k = array_search($e, $event->getArguments(), true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$r = new \ReflectionFunction($event->getController()(...));
|
||||
$r = $r->getParameters()[$k] ?? null;
|
||||
|
||||
if ($r && (!($r = $r->getType()) instanceof \ReflectionNamedType || FlattenException::class === $r->getName())) {
|
||||
$arguments = $event->getArguments();
|
||||
$arguments[$k] = FlattenException::createFromThrowable($e);
|
||||
$event->setArguments($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
KernelEvents::CONTROLLER_ARGUMENTS => 'onControllerArguments',
|
||||
KernelEvents::EXCEPTION => [
|
||||
['logKernelException', 0],
|
||||
['onKernelException', -128],
|
||||
],
|
||||
KernelEvents::RESPONSE => ['removeCspHeader', -128],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an exception.
|
||||
*/
|
||||
protected function logException(\Throwable $exception, string $message, ?string $logLevel = null): void
|
||||
{
|
||||
if (null === $this->logger) {
|
||||
return;
|
||||
}
|
||||
|
||||
$logLevel ??= $this->resolveLogLevel($exception);
|
||||
|
||||
$this->logger->log($logLevel, $message, ['exception' => $exception]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the level to be used when logging the exception.
|
||||
*/
|
||||
private function resolveLogLevel(\Throwable $throwable): string
|
||||
{
|
||||
foreach ($this->exceptionsMapping as $class => $config) {
|
||||
if ($throwable instanceof $class && $config['log_level']) {
|
||||
return $config['log_level'];
|
||||
}
|
||||
}
|
||||
|
||||
$class = new \ReflectionClass($throwable);
|
||||
|
||||
do {
|
||||
if ($attributes = $class->getAttributes(WithLogLevel::class)) {
|
||||
/** @var WithLogLevel $instance */
|
||||
$instance = $attributes[0]->newInstance();
|
||||
|
||||
return $instance->level;
|
||||
}
|
||||
} while ($class = $class->getParentClass());
|
||||
|
||||
if (!$throwable instanceof HttpExceptionInterface || $throwable->getStatusCode() >= 500) {
|
||||
return LogLevel::CRITICAL;
|
||||
}
|
||||
|
||||
return LogLevel::ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones the request for the exception.
|
||||
*/
|
||||
protected function duplicateRequest(\Throwable $exception, Request $request): Request
|
||||
{
|
||||
$attributes = [
|
||||
'_controller' => $this->controller,
|
||||
'exception' => $exception,
|
||||
'logger' => DebugLoggerConfigurator::getDebugLogger($this->logger),
|
||||
];
|
||||
$request = $request->duplicate(null, null, $attributes);
|
||||
$request->setMethod('GET');
|
||||
|
||||
return $request;
|
||||
}
|
||||
}
|
100
vendor/symfony/http-kernel/EventListener/FragmentListener.php
vendored
Normal file
100
vendor/symfony/http-kernel/EventListener/FragmentListener.php
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\EventListener;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\UriSigner;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
|
||||
/**
|
||||
* Handles content fragments represented by special URIs.
|
||||
*
|
||||
* All URL paths starting with /_fragment are handled as
|
||||
* content fragments by this listener.
|
||||
*
|
||||
* Throws an AccessDeniedHttpException exception if the request
|
||||
* is not signed or if it is not an internal sub-request.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class FragmentListener implements EventSubscriberInterface
|
||||
{
|
||||
private UriSigner $signer;
|
||||
private string $fragmentPath;
|
||||
|
||||
/**
|
||||
* @param string $fragmentPath The path that triggers this listener
|
||||
*/
|
||||
public function __construct(UriSigner $signer, string $fragmentPath = '/_fragment')
|
||||
{
|
||||
$this->signer = $signer;
|
||||
$this->fragmentPath = $fragmentPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes request attributes when the path is '/_fragment'.
|
||||
*
|
||||
* @throws AccessDeniedHttpException if the request does not come from a trusted IP
|
||||
*/
|
||||
public function onKernelRequest(RequestEvent $event): void
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
if ($this->fragmentPath !== rawurldecode($request->getPathInfo())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($request->attributes->has('_controller')) {
|
||||
// Is a sub-request: no need to parse _path but it should still be removed from query parameters as below.
|
||||
$request->query->remove('_path');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($event->isMainRequest()) {
|
||||
$this->validateRequest($request);
|
||||
}
|
||||
|
||||
parse_str($request->query->get('_path', ''), $attributes);
|
||||
$attributes['_check_controller_is_allowed'] = -1; // @deprecated, switch to true in Symfony 7
|
||||
$request->attributes->add($attributes);
|
||||
$request->attributes->set('_route_params', array_replace($request->attributes->get('_route_params', []), $attributes));
|
||||
$request->query->remove('_path');
|
||||
}
|
||||
|
||||
protected function validateRequest(Request $request): void
|
||||
{
|
||||
// is the Request safe?
|
||||
if (!$request->isMethodSafe()) {
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
|
||||
// is the Request signed?
|
||||
if ($this->signer->checkRequest($request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
KernelEvents::REQUEST => [['onKernelRequest', 48]],
|
||||
];
|
||||
}
|
||||
}
|
77
vendor/symfony/http-kernel/EventListener/LocaleAwareListener.php
vendored
Normal file
77
vendor/symfony/http-kernel/EventListener/LocaleAwareListener.php
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\EventListener;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Contracts\Translation\LocaleAwareInterface;
|
||||
|
||||
/**
|
||||
* Pass the current locale to the provided services.
|
||||
*
|
||||
* @author Pierre Bobiet <pierrebobiet@gmail.com>
|
||||
*/
|
||||
class LocaleAwareListener implements EventSubscriberInterface
|
||||
{
|
||||
private iterable $localeAwareServices;
|
||||
private RequestStack $requestStack;
|
||||
|
||||
/**
|
||||
* @param iterable<mixed, LocaleAwareInterface> $localeAwareServices
|
||||
*/
|
||||
public function __construct(iterable $localeAwareServices, RequestStack $requestStack)
|
||||
{
|
||||
$this->localeAwareServices = $localeAwareServices;
|
||||
$this->requestStack = $requestStack;
|
||||
}
|
||||
|
||||
public function onKernelRequest(RequestEvent $event): void
|
||||
{
|
||||
$this->setLocale($event->getRequest()->getLocale(), $event->getRequest()->getDefaultLocale());
|
||||
}
|
||||
|
||||
public function onKernelFinishRequest(FinishRequestEvent $event): void
|
||||
{
|
||||
if (null === $parentRequest = $this->requestStack->getParentRequest()) {
|
||||
foreach ($this->localeAwareServices as $service) {
|
||||
$service->setLocale($event->getRequest()->getDefaultLocale());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->setLocale($parentRequest->getLocale(), $parentRequest->getDefaultLocale());
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
// must be registered after the Locale listener
|
||||
KernelEvents::REQUEST => [['onKernelRequest', 15]],
|
||||
KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', -15]],
|
||||
];
|
||||
}
|
||||
|
||||
private function setLocale(string $locale, string $defaultLocale): void
|
||||
{
|
||||
foreach ($this->localeAwareServices as $service) {
|
||||
try {
|
||||
$service->setLocale($locale);
|
||||
} catch (\InvalidArgumentException) {
|
||||
$service->setLocale($defaultLocale);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
95
vendor/symfony/http-kernel/EventListener/LocaleListener.php
vendored
Normal file
95
vendor/symfony/http-kernel/EventListener/LocaleListener.php
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\EventListener;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
|
||||
use Symfony\Component\HttpKernel\Event\KernelEvent;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Component\Routing\RequestContextAwareInterface;
|
||||
|
||||
/**
|
||||
* Initializes the locale based on the current request.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class LocaleListener implements EventSubscriberInterface
|
||||
{
|
||||
private ?RequestContextAwareInterface $router;
|
||||
private string $defaultLocale;
|
||||
private RequestStack $requestStack;
|
||||
private bool $useAcceptLanguageHeader;
|
||||
private array $enabledLocales;
|
||||
|
||||
public function __construct(RequestStack $requestStack, string $defaultLocale = 'en', ?RequestContextAwareInterface $router = null, bool $useAcceptLanguageHeader = false, array $enabledLocales = [])
|
||||
{
|
||||
$this->defaultLocale = $defaultLocale;
|
||||
$this->requestStack = $requestStack;
|
||||
$this->router = $router;
|
||||
$this->useAcceptLanguageHeader = $useAcceptLanguageHeader;
|
||||
$this->enabledLocales = $enabledLocales;
|
||||
}
|
||||
|
||||
public function setDefaultLocale(KernelEvent $event): void
|
||||
{
|
||||
$event->getRequest()->setDefaultLocale($this->defaultLocale);
|
||||
}
|
||||
|
||||
public function onKernelRequest(RequestEvent $event): void
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
$this->setLocale($request);
|
||||
$this->setRouterContext($request);
|
||||
}
|
||||
|
||||
public function onKernelFinishRequest(FinishRequestEvent $event): void
|
||||
{
|
||||
if (null !== $parentRequest = $this->requestStack->getParentRequest()) {
|
||||
$this->setRouterContext($parentRequest);
|
||||
}
|
||||
}
|
||||
|
||||
private function setLocale(Request $request): void
|
||||
{
|
||||
if ($locale = $request->attributes->get('_locale')) {
|
||||
$request->setLocale($locale);
|
||||
} elseif ($this->useAcceptLanguageHeader) {
|
||||
if ($request->getLanguages() && $preferredLanguage = $request->getPreferredLanguage($this->enabledLocales)) {
|
||||
$request->setLocale($preferredLanguage);
|
||||
}
|
||||
$request->attributes->set('_vary_by_language', true);
|
||||
}
|
||||
}
|
||||
|
||||
private function setRouterContext(Request $request): void
|
||||
{
|
||||
$this->router?->getContext()->setParameter('_locale', $request->getLocale());
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
KernelEvents::REQUEST => [
|
||||
['setDefaultLocale', 100],
|
||||
// must be registered after the Router to have access to the _locale
|
||||
['onKernelRequest', 16],
|
||||
],
|
||||
KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', 0]],
|
||||
];
|
||||
}
|
||||
}
|
150
vendor/symfony/http-kernel/EventListener/ProfilerListener.php
vendored
Normal file
150
vendor/symfony/http-kernel/EventListener/ProfilerListener.php
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\EventListener;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
|
||||
use Symfony\Component\HttpKernel\Event\ResponseEvent;
|
||||
use Symfony\Component\HttpKernel\Event\TerminateEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Component\HttpKernel\Profiler\Profile;
|
||||
use Symfony\Component\HttpKernel\Profiler\Profiler;
|
||||
|
||||
/**
|
||||
* ProfilerListener collects data for the current request by listening to the kernel events.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class ProfilerListener implements EventSubscriberInterface
|
||||
{
|
||||
private Profiler $profiler;
|
||||
private ?RequestMatcherInterface $matcher;
|
||||
private bool $onlyException;
|
||||
private bool $onlyMainRequests;
|
||||
private ?\Throwable $exception = null;
|
||||
/** @var \SplObjectStorage<Request, Profile> */
|
||||
private \SplObjectStorage $profiles;
|
||||
private RequestStack $requestStack;
|
||||
private ?string $collectParameter;
|
||||
/** @var \SplObjectStorage<Request, Request|null> */
|
||||
private \SplObjectStorage $parents;
|
||||
|
||||
/**
|
||||
* @param bool $onlyException True if the profiler only collects data when an exception occurs, false otherwise
|
||||
* @param bool $onlyMainRequests True if the profiler only collects data when the request is the main request, false otherwise
|
||||
*/
|
||||
public function __construct(Profiler $profiler, RequestStack $requestStack, ?RequestMatcherInterface $matcher = null, bool $onlyException = false, bool $onlyMainRequests = false, ?string $collectParameter = null)
|
||||
{
|
||||
$this->profiler = $profiler;
|
||||
$this->matcher = $matcher;
|
||||
$this->onlyException = $onlyException;
|
||||
$this->onlyMainRequests = $onlyMainRequests;
|
||||
$this->profiles = new \SplObjectStorage();
|
||||
$this->parents = new \SplObjectStorage();
|
||||
$this->requestStack = $requestStack;
|
||||
$this->collectParameter = $collectParameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the onKernelException event.
|
||||
*/
|
||||
public function onKernelException(ExceptionEvent $event): void
|
||||
{
|
||||
if ($this->onlyMainRequests && !$event->isMainRequest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->exception = $event->getThrowable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the onKernelResponse event.
|
||||
*/
|
||||
public function onKernelResponse(ResponseEvent $event): void
|
||||
{
|
||||
if ($this->onlyMainRequests && !$event->isMainRequest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->onlyException && null === $this->exception) {
|
||||
return;
|
||||
}
|
||||
|
||||
$request = $event->getRequest();
|
||||
if (null !== $this->collectParameter && null !== $collectParameterValue = $request->get($this->collectParameter)) {
|
||||
true === $collectParameterValue || filter_var($collectParameterValue, \FILTER_VALIDATE_BOOL) ? $this->profiler->enable() : $this->profiler->disable();
|
||||
}
|
||||
|
||||
$exception = $this->exception;
|
||||
$this->exception = null;
|
||||
|
||||
if (null !== $this->matcher && !$this->matcher->matches($request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$session = $request->hasPreviousSession() ? $request->getSession() : null;
|
||||
|
||||
if ($session instanceof Session) {
|
||||
$usageIndexValue = $usageIndexReference = &$session->getUsageIndex();
|
||||
$usageIndexReference = \PHP_INT_MIN;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!$profile = $this->profiler->collect($request, $event->getResponse(), $exception)) {
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
if ($session instanceof Session) {
|
||||
$usageIndexReference = $usageIndexValue;
|
||||
}
|
||||
}
|
||||
|
||||
$this->profiles[$request] = $profile;
|
||||
|
||||
$this->parents[$request] = $this->requestStack->getParentRequest();
|
||||
}
|
||||
|
||||
public function onKernelTerminate(TerminateEvent $event): void
|
||||
{
|
||||
// attach children to parents
|
||||
foreach ($this->profiles as $request) {
|
||||
if (null !== $parentRequest = $this->parents[$request]) {
|
||||
if (isset($this->profiles[$parentRequest])) {
|
||||
$this->profiles[$parentRequest]->addChild($this->profiles[$request]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// save profiles
|
||||
foreach ($this->profiles as $request) {
|
||||
$this->profiler->saveProfile($this->profiles[$request]);
|
||||
}
|
||||
|
||||
$this->profiles = new \SplObjectStorage();
|
||||
$this->parents = new \SplObjectStorage();
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
KernelEvents::RESPONSE => ['onKernelResponse', -100],
|
||||
KernelEvents::EXCEPTION => ['onKernelException', 0],
|
||||
KernelEvents::TERMINATE => ['onKernelTerminate', -1024],
|
||||
];
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user