[
  {
    "path": ".gitattributes",
    "content": "/Tests export-ignore\n/phpunit.xml.dist export-ignore\n/.git* export-ignore\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "Please do not submit any Pull Requests here. They will be closed.\n---\n\nPlease submit your PR here instead:\nhttps://github.com/symfony/symfony\n\nThis repository is what we call a \"subtree split\": a read-only subset of that main repository.\nWe're looking forward to your PR there!\n"
  },
  {
    "path": ".github/workflows/close-pull-request.yml",
    "content": "name: Close Pull Request\n\non:\n  pull_request_target:\n    types: [opened]\n\njobs:\n  run:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: superbrothers/close-pull-request@v3\n      with:\n        comment: |\n          Thanks for your Pull Request! We love contributions.\n\n          However, you should instead open your PR on the main repository:\n          https://github.com/symfony/symfony\n\n          This repository is what we call a \"subtree split\": a read-only subset of that main repository.\n          We're looking forward to your PR there!\n"
  },
  {
    "path": ".gitignore",
    "content": "vendor/\ncomposer.lock\nphpunit.xml\nTests/Fixtures/cache/\nTests/Fixtures/logs/\n"
  },
  {
    "path": "Attribute/AsController.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Attribute;\n\n/**\n * Autoconfigures controllers as services by applying\n * the `controller.service_arguments` tag to them.\n *\n * This enables injecting services as method arguments in addition\n * to other conventional dependency injection strategies.\n */\n#[\\Attribute(\\Attribute::TARGET_CLASS | \\Attribute::TARGET_FUNCTION)]\nclass AsController\n{\n}\n"
  },
  {
    "path": "Attribute/AsTargetedValueResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Attribute;\n\n/**\n * Service tag to autoconfigure targeted value resolvers.\n */\n#[\\Attribute(\\Attribute::TARGET_CLASS)]\nclass AsTargetedValueResolver\n{\n    /**\n     * @param string|null $name The name with which the resolver can be targeted\n     */\n    public function __construct(public readonly ?string $name = null)\n    {\n    }\n}\n"
  },
  {
    "path": "Attribute/Cache.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Attribute;\n\nuse Symfony\\Component\\ExpressionLanguage\\Expression;\nuse Symfony\\Component\\HttpFoundation\\Request;\n\n/**\n * Describes the default HTTP cache headers on controllers.\n * Headers defined in the Cache attribute are ignored if they are already set\n * by the controller.\n *\n * @see https://symfony.com/doc/current/http_cache.html#making-your-responses-http-cacheable\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\n#[\\Attribute(\\Attribute::TARGET_CLASS | \\Attribute::TARGET_METHOD | \\Attribute::TARGET_FUNCTION | \\Attribute::IS_REPEATABLE)]\nfinal class Cache\n{\n    /**\n     * @internal\n     */\n    public public(set) readonly array $variables;\n\n    public function __construct(\n        /**\n         * The expiration date as a valid date for the strtotime() function.\n         */\n        public ?string $expires = null,\n\n        /**\n         * The number of seconds that the response is considered fresh by a private\n         * cache like a web browser.\n         */\n        public int|string|null $maxage = null,\n\n        /**\n         * The number of seconds that the response is considered fresh by a public\n         * cache like a reverse proxy cache.\n         */\n        public int|string|null $smaxage = null,\n\n        /**\n         * If true, the contents will be stored in a public cache and served to all\n         * the next requests.\n         */\n        public ?bool $public = null,\n\n        /**\n         * If true, the response is not served stale by a cache in any circumstance\n         * without first revalidating with the origin.\n         */\n        public bool $mustRevalidate = false,\n\n        /**\n         * Set \"Vary\" header.\n         *\n         * Example:\n         * ['Accept-Encoding', 'User-Agent']\n         *\n         * @see https://symfony.com/doc/current/http_cache/cache_vary.html\n         *\n         * @var string[]\n         */\n        public array $vary = [],\n\n        /**\n         * A value evaluated to compute the Last-Modified HTTP header.\n         *\n         * The value may be either an ExpressionLanguage expression or a Closure and\n         * receives all the request attributes and the resolved controller arguments.\n         *\n         * The result must be an instance of \\DateTimeInterface.\n         *\n         * @var \\DateTimeInterface|string|Expression|\\Closure(array<string, mixed>, Request, ?object):\\DateTimeInterface|null\n         */\n        public \\DateTimeInterface|string|Expression|\\Closure|null $lastModified = null,\n\n        /**\n         * A value evaluated to compute the ETag HTTP header.\n         *\n         * The value may be either an ExpressionLanguage expression or a Closure and\n         * receives all the request attributes and the resolved controller arguments.\n         *\n         * The result must be a string that will be hashed.\n         *\n         * @var string|Expression|\\Closure(array<string, mixed>, Request, ?object):string|null\n         */\n        public string|Expression|\\Closure|null $etag = null,\n\n        /**\n         * max-stale Cache-Control header\n         * It can be expressed in seconds or with a relative time format (1 day, 2 weeks, ...).\n         */\n        public int|string|null $maxStale = null,\n\n        /**\n         * stale-while-revalidate Cache-Control header\n         * It can be expressed in seconds or with a relative time format (1 day, 2 weeks, ...).\n         */\n        public int|string|null $staleWhileRevalidate = null,\n\n        /**\n         * stale-if-error Cache-Control header\n         * It can be expressed in seconds or with a relative time format (1 day, 2 weeks, ...).\n         */\n        public int|string|null $staleIfError = null,\n\n        /**\n         * Add the \"no-store\" Cache-Control directive when set to true.\n         *\n         * This directive indicates that no part of the response can be cached\n         * in any cache (not in a shared cache, nor in a private cache).\n         *\n         * Supersedes the \"$public\" and \"$smaxage\" values.\n         *\n         * @see https://datatracker.ietf.org/doc/html/rfc7234#section-5.2.2.3\n         */\n        public ?bool $noStore = null,\n\n        /**\n         * A value evaluated to determine whether the cache attribute should be applied.\n         *\n         * The value may be either an ExpressionLanguage expression or a Closure and\n         * receives all the request attributes and the resolved controller arguments.\n         *\n         * The result must be a boolean. If true the attribute is applied, if false it is ignored.\n         *\n         * @var bool|string|Expression|\\Closure(array<string, mixed>, Request, ?object):bool\n         */\n        public bool|string|Expression|\\Closure $if = true,\n    ) {\n    }\n}\n"
  },
  {
    "path": "Attribute/IsSignatureValid.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Attribute;\n\n/**\n * Validates the request signature for specific HTTP methods.\n *\n * This class determines whether a request's signature should be validated\n * based on the configured HTTP methods. If the request method matches one\n * of the specified methods (or if no methods are specified), the signature\n * is checked.\n *\n * If the signature is invalid, a {@see \\Symfony\\Component\\HttpFoundation\\Exception\\SignedUriException}\n * is thrown during validation.\n *\n * @author Santiago San Martin <sanmartindev@gmail.com>\n */\n#[\\Attribute(\\Attribute::IS_REPEATABLE | \\Attribute::TARGET_CLASS | \\Attribute::TARGET_METHOD | \\Attribute::TARGET_FUNCTION)]\nfinal class IsSignatureValid\n{\n    /** @var string[] */\n    public readonly array $methods;\n\n    /**\n     * @param string[]|string $methods HTTP methods that require signature validation. An empty array means that no method filtering is done\n     */\n    public function __construct(\n        array|string $methods = [],\n    ) {\n        $this->methods = (array) $methods;\n    }\n}\n"
  },
  {
    "path": "Attribute/MapDateTime.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Attribute;\n\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\DateTimeValueResolver;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\n\n/**\n * Controller parameter tag to configure DateTime arguments.\n */\n#[\\Attribute(\\Attribute::TARGET_PARAMETER)]\nclass MapDateTime extends ValueResolver\n{\n    /**\n     * @param string|null                                 $format   The DateTime format to use, @see https://php.net/datetime.format\n     * @param bool                                        $disabled Whether this value resolver is disabled; this allows to enable a value resolver globally while disabling it in specific cases\n     * @param class-string<ValueResolverInterface>|string $resolver The name of the resolver to use\n     */\n    public function __construct(\n        public readonly ?string $format = null,\n        bool $disabled = false,\n        string $resolver = DateTimeValueResolver::class,\n    ) {\n        parent::__construct($resolver, $disabled);\n    }\n}\n"
  },
  {
    "path": "Attribute/MapQueryParameter.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Attribute;\n\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\QueryParameterValueResolver;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\n\n/**\n * Can be used to pass a query parameter to a controller argument.\n *\n * @author Ruud Kamphuis <ruud@ticketswap.com>\n * @author Ionut Enache <i.ovidiuenache@yahoo.com>\n */\n#[\\Attribute(\\Attribute::TARGET_PARAMETER)]\nfinal class MapQueryParameter extends ValueResolver\n{\n    /**\n     * @see https://php.net/manual/filter.constants for filter, flags and options\n     *\n     * @param string|null                                         $name     The name of the query parameter; if null, the name of the argument in the controller will be used\n     * @param (FILTER_VALIDATE_*)|(FILTER_SANITIZE_*)|null        $filter   The filter to pass to \"filter_var()\", deduced from the type-hint if null\n     * @param int-mask-of<(FILTER_FLAG_*)|FILTER_NULL_ON_FAILURE> $flags\n     * @param array{min_range?: int|float, max_range?: int|float, regexp?: string, ...} $options\n     * @param class-string<ValueResolverInterface>|string         $resolver The name of the resolver to use\n     */\n    public function __construct(\n        public ?string $name = null,\n        public ?int $filter = null,\n        public int $flags = 0,\n        public array $options = [],\n        string $resolver = QueryParameterValueResolver::class,\n        public int $validationFailedStatusCode = Response::HTTP_NOT_FOUND,\n    ) {\n        parent::__construct($resolver);\n    }\n}\n"
  },
  {
    "path": "Attribute/MapQueryString.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Attribute;\n\nuse Symfony\\Component\\ExpressionLanguage\\Expression;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\RequestPayloadValueResolver;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\Validator\\Constraints\\GroupSequence;\n\n/**\n * Controller parameter tag to map the query string of the request to typed object and validate it.\n *\n * @psalm-import-type GroupResolver from RequestPayloadValueResolver\n *\n * @author Konstantin Myakshin <molodchick@gmail.com>\n */\n#[\\Attribute(\\Attribute::TARGET_PARAMETER)]\nclass MapQueryString extends ValueResolver\n{\n    public ArgumentMetadata $metadata;\n\n    /**\n     * @param array<string, mixed>                                             $serializationContext       The serialization context to use when deserializing the query string\n     * @param string|Expression|GroupSequence|GroupResolver|array<string>|null $validationGroups           The validation groups to use when validating the query string mapping\n     * @param class-string                                                     $resolver                   The class name of the resolver to use\n     * @param int                                                              $validationFailedStatusCode The HTTP code to return if the validation fails\n     */\n    public function __construct(\n        public readonly array $serializationContext = [],\n        public readonly string|Expression|GroupSequence|\\Closure|array|null $validationGroups = null,\n        string $resolver = RequestPayloadValueResolver::class,\n        public readonly int $validationFailedStatusCode = Response::HTTP_NOT_FOUND,\n        public readonly ?string $key = null,\n        public bool $mapWhenEmpty = false,\n    ) {\n        parent::__construct($resolver);\n    }\n}\n"
  },
  {
    "path": "Attribute/MapRequestHeader.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Attribute;\n\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\RequestHeaderValueResolver;\n\n#[\\Attribute(\\Attribute::TARGET_PARAMETER)]\nfinal class MapRequestHeader extends ValueResolver\n{\n    /**\n     * @param string|null  $name                       The name of the header parameter; if null, the name of the argument in the controller will be used\n     * @param class-string $resolver                   The class name of the resolver to use\n     * @param int          $validationFailedStatusCode The HTTP code to return if the validation fails\n     */\n    public function __construct(\n        public readonly ?string $name = null,\n        string $resolver = RequestHeaderValueResolver::class,\n        public readonly int $validationFailedStatusCode = Response::HTTP_BAD_REQUEST,\n    ) {\n        parent::__construct($resolver);\n    }\n}\n"
  },
  {
    "path": "Attribute/MapRequestPayload.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Attribute;\n\nuse Symfony\\Component\\ExpressionLanguage\\Expression;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\RequestPayloadValueResolver;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\Validator\\Constraints\\GroupSequence;\n\n/**\n * Controller parameter tag to map the request content to typed object and validate it.\n *\n * @psalm-import-type GroupResolver from RequestPayloadValueResolver\n *\n * @author Konstantin Myakshin <molodchick@gmail.com>\n */\n#[\\Attribute(\\Attribute::TARGET_PARAMETER)]\nclass MapRequestPayload extends ValueResolver\n{\n    public ArgumentMetadata $metadata;\n\n    /**\n     * @param array<string>|string|null                                        $acceptFormat               The payload formats to accept (i.e. \"json\", \"xml\")\n     * @param array<string, mixed>                                             $serializationContext       The serialization context to use when deserializing the payload\n     * @param string|Expression|GroupSequence|GroupResolver|array<string>|null $validationGroups           The validation groups to use when validating the query string mapping\n     * @param class-string                                                     $resolver                   The class name of the resolver to use\n     * @param int                                                              $validationFailedStatusCode The HTTP code to return if the validation fails\n     * @param class-string|string|null                                         $type                       The element type for array deserialization\n     */\n    public function __construct(\n        public readonly array|string|null $acceptFormat = null,\n        public readonly array $serializationContext = [],\n        public readonly string|Expression|GroupSequence|\\Closure|array|null $validationGroups = null,\n        string $resolver = RequestPayloadValueResolver::class,\n        public readonly int $validationFailedStatusCode = Response::HTTP_UNPROCESSABLE_ENTITY,\n        public readonly ?string $type = null,\n        public bool $mapWhenEmpty = false,\n    ) {\n        parent::__construct($resolver);\n    }\n}\n"
  },
  {
    "path": "Attribute/MapUploadedFile.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Attribute;\n\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\RequestPayloadValueResolver;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\Validator\\Constraint;\n\n#[\\Attribute(\\Attribute::TARGET_PARAMETER)]\nclass MapUploadedFile extends ValueResolver\n{\n    public ArgumentMetadata $metadata;\n\n    public function __construct(\n        /** @var Constraint|array<Constraint>|null */\n        public Constraint|array|null $constraints = null,\n        public ?string $name = null,\n        string $resolver = RequestPayloadValueResolver::class,\n        public readonly int $validationFailedStatusCode = Response::HTTP_UNPROCESSABLE_ENTITY,\n    ) {\n        parent::__construct($resolver);\n    }\n}\n"
  },
  {
    "path": "Attribute/Serialize.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Attribute;\n\n/**\n * Controller tag to serialize response.\n *\n * @author Konstantin Myakshin <molodchick@gmail.com>\n */\n#[\\Attribute(\\Attribute::TARGET_METHOD)]\nfinal class Serialize\n{\n    /**\n     * @param int                  $code    The HTTP status code (200 \"OK\" by default)\n     * @param array<string, mixed> $headers Extra headers to set on the response\n     * @param array<string, mixed> $context The serialization context passed to the serializer\n     */\n    public function __construct(\n        public readonly int $code = 200,\n        public readonly array $headers = [],\n        public readonly array $context = [],\n    ) {\n    }\n}\n"
  },
  {
    "path": "Attribute/ValueResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Attribute;\n\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\n\n/**\n * Defines which value resolver should be used for a given parameter.\n */\n#[\\Attribute(\\Attribute::TARGET_PARAMETER | \\Attribute::IS_REPEATABLE)]\nclass ValueResolver\n{\n    /**\n     * @param class-string<ValueResolverInterface>|string $resolver The class name of the resolver to use\n     * @param bool                                        $disabled Whether this value resolver is disabled; this allows to enable a value resolver globally while disabling it in specific cases\n     */\n    public function __construct(\n        public string $resolver,\n        public bool $disabled = false,\n    ) {\n    }\n}\n"
  },
  {
    "path": "Attribute/WithHttpStatus.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Attribute;\n\n/**\n * Defines the HTTP status code applied to an exception.\n *\n * @author Dejan Angelov <angelovdejan@protonmail.com>\n */\n#[\\Attribute(\\Attribute::TARGET_CLASS)]\nclass WithHttpStatus\n{\n    /**\n     * @param int                   $statusCode The HTTP status code to use\n     * @param array<string, string> $headers    The HTTP headers to add to the response\n     */\n    public function __construct(\n        public readonly int $statusCode,\n        public readonly array $headers = [],\n    ) {\n    }\n}\n"
  },
  {
    "path": "Attribute/WithLogLevel.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Attribute;\n\nuse Psr\\Log\\LogLevel;\n\n/**\n * Defines the log level applied to an exception.\n *\n * @author Dejan Angelov <angelovdejan@protonmail.com>\n */\n#[\\Attribute(\\Attribute::TARGET_CLASS)]\nfinal class WithLogLevel\n{\n    /**\n     * @param LogLevel::* $level The level to use to log the exception\n     */\n    public function __construct(public readonly string $level)\n    {\n        if (!\\defined('Psr\\Log\\LogLevel::'.strtoupper($this->level))) {\n            throw new \\InvalidArgumentException(\\sprintf('Invalid log level \"%s\".', $this->level));\n        }\n    }\n}\n"
  },
  {
    "path": "Bundle/AbstractBundle.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Bundle;\n\nuse Symfony\\Component\\Config\\Definition\\Configurator\\DefinitionConfigurator;\nuse Symfony\\Component\\DependencyInjection\\Container;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Extension\\ConfigurableExtensionInterface;\nuse Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface;\nuse Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ContainerConfigurator;\n\n/**\n * A Bundle that provides configuration hooks.\n *\n * @author Yonel Ceruto <yonelceruto@gmail.com>\n */\nabstract class AbstractBundle extends Bundle implements ConfigurableExtensionInterface\n{\n    protected string $extensionAlias = '';\n\n    public function configure(DefinitionConfigurator $definition): void\n    {\n    }\n\n    public function prependExtension(ContainerConfigurator $container, ContainerBuilder $builder): void\n    {\n    }\n\n    public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void\n    {\n    }\n\n    public function getContainerExtension(): ?ExtensionInterface\n    {\n        if ('' === $this->extensionAlias) {\n            $this->extensionAlias = Container::underscore(preg_replace('/Bundle$/', '', $this->getName()));\n        }\n\n        return $this->extension ??= new BundleExtension($this, $this->extensionAlias);\n    }\n\n    public function getPath(): string\n    {\n        if (!isset($this->path)) {\n            $reflected = new \\ReflectionObject($this);\n            // assume the modern directory structure by default\n            $this->path = \\dirname($reflected->getFileName(), 2);\n        }\n\n        return $this->path;\n    }\n}\n"
  },
  {
    "path": "Bundle/Bundle.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Bundle;\n\nuse Symfony\\Component\\Console\\Application;\nuse Symfony\\Component\\DependencyInjection\\Container;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\ContainerInterface;\nuse Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface;\n\n/**\n * An implementation of BundleInterface that adds a few conventions for DependencyInjection extensions.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nabstract class Bundle implements BundleInterface\n{\n    protected string $name;\n    protected ExtensionInterface|false|null $extension = null;\n    protected string $path;\n    protected ?ContainerInterface $container;\n\n    private string $namespace;\n\n    public function boot(): void\n    {\n    }\n\n    public function shutdown(): void\n    {\n    }\n\n    /**\n     * This method can be overridden to register compilation passes,\n     * other extensions, ...\n     */\n    public function build(ContainerBuilder $container): void\n    {\n    }\n\n    /**\n     * Returns the bundle's container extension.\n     *\n     * @throws \\LogicException\n     */\n    public function getContainerExtension(): ?ExtensionInterface\n    {\n        if (!isset($this->extension)) {\n            $extension = $this->createContainerExtension();\n\n            if (null !== $extension) {\n                if (!$extension instanceof ExtensionInterface) {\n                    throw new \\LogicException(\\sprintf('Extension \"%s\" must implement Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface.', get_debug_type($extension)));\n                }\n\n                // check naming convention\n                $basename = preg_replace('/Bundle$/', '', $this->getName());\n                $expectedAlias = Container::underscore($basename);\n\n                if ($expectedAlias != $extension->getAlias()) {\n                    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()));\n                }\n\n                $this->extension = $extension;\n            } else {\n                $this->extension = false;\n            }\n        }\n\n        return $this->extension ?: null;\n    }\n\n    public function getNamespace(): string\n    {\n        if (!isset($this->namespace)) {\n            $this->parseClassName();\n        }\n\n        return $this->namespace;\n    }\n\n    public function getPath(): string\n    {\n        if (!isset($this->path)) {\n            $reflected = new \\ReflectionObject($this);\n            $this->path = \\dirname($reflected->getFileName());\n        }\n\n        return $this->path;\n    }\n\n    /**\n     * Returns the bundle name (the class short name).\n     */\n    final public function getName(): string\n    {\n        if (!isset($this->name)) {\n            $this->parseClassName();\n        }\n\n        return $this->name;\n    }\n\n    public function registerCommands(Application $application): void\n    {\n    }\n\n    /**\n     * Returns the bundle's container extension class.\n     */\n    protected function getContainerExtensionClass(): string\n    {\n        $basename = preg_replace('/Bundle$/', '', $this->getName());\n\n        return $this->getNamespace().'\\\\DependencyInjection\\\\'.$basename.'Extension';\n    }\n\n    /**\n     * Creates the bundle's container extension.\n     */\n    protected function createContainerExtension(): ?ExtensionInterface\n    {\n        return class_exists($class = $this->getContainerExtensionClass()) ? new $class() : null;\n    }\n\n    private function parseClassName(): void\n    {\n        $pos = strrpos(static::class, '\\\\');\n        $this->namespace = false === $pos ? '' : substr(static::class, 0, $pos);\n        $this->name ??= false === $pos ? static::class : substr(static::class, $pos + 1);\n    }\n\n    public function setContainer(?ContainerInterface $container): void\n    {\n        $this->container = $container;\n    }\n}\n"
  },
  {
    "path": "Bundle/BundleExtension.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Bundle;\n\nuse Symfony\\Component\\Config\\Definition\\Configuration;\nuse Symfony\\Component\\Config\\Definition\\ConfigurationInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Extension\\ConfigurableExtensionInterface;\nuse Symfony\\Component\\DependencyInjection\\Extension\\Extension;\nuse Symfony\\Component\\DependencyInjection\\Extension\\ExtensionTrait;\nuse Symfony\\Component\\DependencyInjection\\Extension\\PrependExtensionInterface;\nuse Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ContainerConfigurator;\n\n/**\n * @author Yonel Ceruto <yonelceruto@gmail.com>\n *\n * @internal\n */\nclass BundleExtension extends Extension implements PrependExtensionInterface\n{\n    use ExtensionTrait;\n\n    public function __construct(\n        private ConfigurableExtensionInterface $subject,\n        private string $alias,\n    ) {\n    }\n\n    public function getConfiguration(array $config, ContainerBuilder $container): ?ConfigurationInterface\n    {\n        return new Configuration($this->subject, $container, $this->getAlias());\n    }\n\n    public function getAlias(): string\n    {\n        return $this->alias;\n    }\n\n    public function prepend(ContainerBuilder $container): void\n    {\n        $callback = function (ContainerConfigurator $configurator) use ($container) {\n            $this->subject->prependExtension($configurator, $container);\n        };\n\n        $this->executeConfiguratorCallback($container, $callback, $this->subject, true);\n    }\n\n    public function load(array $configs, ContainerBuilder $container): void\n    {\n        $config = $this->processConfiguration($this->getConfiguration([], $container), $configs);\n\n        $callback = function (ContainerConfigurator $configurator) use ($config, $container) {\n            $this->subject->loadExtension($config, $configurator, $container);\n        };\n\n        $this->executeConfiguratorCallback($container, $callback, $this->subject);\n    }\n}\n"
  },
  {
    "path": "Bundle/BundleInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Bundle;\n\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\ContainerInterface;\nuse Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface;\n\n/**\n * BundleInterface.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface BundleInterface\n{\n    /**\n     * Boots the Bundle.\n     */\n    public function boot(): void;\n\n    /**\n     * Shutdowns the Bundle.\n     */\n    public function shutdown(): void;\n\n    /**\n     * Builds the bundle.\n     *\n     * It is only ever called once when the cache is empty.\n     */\n    public function build(ContainerBuilder $container): void;\n\n    /**\n     * Returns the container extension that should be implicitly loaded.\n     */\n    public function getContainerExtension(): ?ExtensionInterface;\n\n    /**\n     * Returns the bundle name (the class short name).\n     */\n    public function getName(): string;\n\n    /**\n     * Gets the Bundle namespace.\n     */\n    public function getNamespace(): string;\n\n    /**\n     * Gets the Bundle directory path.\n     *\n     * The path should always be returned as a Unix path (with /).\n     */\n    public function getPath(): string;\n\n    public function setContainer(?ContainerInterface $container): void;\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "CHANGELOG\n=========\n\n8.1\n---\n\n * Add `#[MapRequestHeader]` to map a header from `Request` to a controller argument\n * Add `hasErrors()` method to `Profile` to track profiles with errors (exceptions or error-level logs)\n * Validate typed route parameters before calling controllers and return an HTTP error when an invalid value is provided\n * Add `ControllerAttributeEvent` et al. to dispatch events named after controller attributes\n * Add support for `UploadedFile` when using `MapRequestPayload`\n * Add support for bundles as compiler pass\n * Add support for `SOURCE_DATE_EPOCH` environment variable\n * Add property `$controllerMetadata` to several kernel events to give listeners access to controller metadata\n * Add `Request` attribute `_controller_attributes` to decouple controller attributes from their source code\n * Return attributes as a flat list when using `Controller[Arguments]Event::getAttributes('*')`\n * Pass `request` and `args` variables to `Cache` attribute expressions containing the `Request` object and controller arguments\n * Allow using closures with the `Cache` attribute\n * Allow setting a condition when the `Cache` attribute should be applied\n * Add `ControllerEvent::evaluate()` et al. to help with evaluating expressions or closures in controller attributes\n * Deprecate passing a non-flat list of attributes to `Controller::setController()`\n * Deprecate the `Symfony\\Component\\HttpKernel\\DependencyInjection\\Extension` class, use the parent `Symfony\\Component\\DependencyInjection\\Extension\\Extension` class instead\n * Allow using Expression or \\Closure for `validationGroups` in `#[MapRequestPayload]` and `#[MapQueryString]`\n * Deprecate passing a `ControllerArgumentsEvent` to the `ViewEvent` constructor; pass a `ControllerArgumentsMetadata` instead\n * Support variadic argument with `#[MapRequestPayload]`\n * Add `#[Serialize]` to serialize values returned by controllers\n * Add argument `$mapWhenEmpty` to `MapQueryString` and `MapRequestPayload` for always attempting denormalization with empty query and request payload\n\n8.0\n---\n\n * Remove `AddAnnotatedClassesToCachePass`\n * Remove `Extension::getAnnotatedClassesToCompile()` and `Extension::addAnnotatedClassesToCompile()`\n * Remove `Kernel::getAnnotatedClassesToCompile()` and `Kernel::setAnnotatedClassCache()`\n * Make `ServicesResetter` class `final`\n * Add argument `$logChannel` to `ErrorListener::logException()`\n * Add argument `$event` to `DumpListener::configure()`\n * Replace `__sleep/wakeup()` by `__(un)serialize()` on kernels and data collectors\n * Add method `getShareDir()` to `KernelInterface`\n\n7.4\n---\n\n * Add support for the `QUERY` HTTP method\n * Deprecate implementing `__sleep/wakeup()` on kernels; use `__(un)serialize()` instead\n * Deprecate implementing `__sleep/wakeup()` on data collectors; use `__(un)serialize()` instead\n * Add `#[IsSignatureValid]` attribute to validate URI signatures\n * Make `Profile` final and `Profiler::__sleep()` internal\n * Collect the application runner class\n * Allow configuring `DumpListener` to use a different dumper when CLI profiling is enabled\n\n7.3\n---\n\n * Record a `waiting` trace in the `HttpCache` when the cache had to wait for another request to finish\n * Add `$key` argument to `#[MapQueryString]` that allows using a specific key for argument resolving\n * Support `Uid` in `#[MapQueryParameter]`\n * Add `ServicesResetterInterface`, implemented by `ServicesResetter`\n * Allow configuring the logging channel per type of exceptions in ErrorListener\n\n7.2\n---\n\n * Remove `@internal` flag and add `@final` to `ServicesResetter`\n * Add support for `SYMFONY_DISABLE_RESOURCE_TRACKING` env var\n * Add support for configuring trusted proxies/headers/hosts via env vars\n\n7.1\n---\n\n * Add method `isKernelTerminating()` to `ExceptionEvent` that allows to check if an exception was thrown while the kernel is being terminated\n * Add `HttpException::fromStatusCode()`\n * Add `$validationFailedStatusCode` argument to `#[MapQueryParameter]` that allows setting a custom HTTP status code when validation fails\n * Add `NearMissValueResolverException` to let value resolvers report when an argument could be under their watch but failed to be resolved\n * Add `$type` argument to `#[MapRequestPayload]` that allows mapping a list of items\n * The `Extension` class is marked as internal, extend the `Extension` class from the DependencyInjection component instead\n * Deprecate `Extension::addAnnotatedClassesToCompile()`\n * Deprecate `AddAnnotatedClassesToCachePass`\n * Deprecate the `setAnnotatedClassCache()` and `getAnnotatedClassesToCompile()` methods of the `Kernel` class\n * Add `#[MapUploadedFile]` attribute to fetch, validate, and inject uploaded files into controller arguments\n\n7.0\n---\n\n * Add argument `$reflector` to `ArgumentResolverInterface::getArguments()` and `ArgumentMetadataFactoryInterface::createArgumentMetadata()`\n * Remove `ArgumentValueResolverInterface`, use `ValueResolverInterface` instead\n * Remove `StreamedResponseListener`\n * Remove `AbstractSurrogate::$phpEscapeMap`\n * Remove `HttpKernelInterface::MASTER_REQUEST`\n * Remove `terminate_on_cache_hit` option from `HttpCache`\n * Require explicit argument when calling `ConfigDataCollector::setKernel()`, `RouterListener::setCurrentRequest()`\n * Remove `Kernel::stripComments()`\n * Remove `FileLinkFormatter`, use `FileLinkFormatter` from the ErrorHandler component instead\n * Remove `UriSigner`, use `UriSigner` from the HttpFoundation component instead\n * Add argument `$buildDir` to `WarmableInterface`\n * Add argument `$filter` to `Profiler::find()` and `FileProfilerStorage::find()`\n\n6.4\n---\n\n * Support backed enums in #[MapQueryParameter]\n * `BundleInterface` no longer extends `ContainerAwareInterface`\n * Add optional `$className` parameter to `ControllerEvent::getAttributes()`\n * Add native return types to `TraceableEventDispatcher` and to `MergeExtensionConfigurationPass`\n * Add argument `$validationFailedStatusCode` to `#[MapQueryString]` and `#[MapRequestPayload]`\n * Add argument `$debug` to `Logger`\n * Add class `DebugLoggerConfigurator`\n * Add parameters `kernel.runtime_mode` and `kernel.runtime_mode.*`, all set from env var `APP_RUNTIME_MODE`\n * Deprecate `Kernel::stripComments()`\n * Support the `!` character at the beginning of a string as a negation operator in the url filter of the profiler\n * Deprecate `UriSigner`, use `UriSigner` from the HttpFoundation component instead\n * Deprecate `FileLinkFormatter`, use `FileLinkFormatter` from the ErrorHandler component instead\n * Add argument `$buildDir` to `WarmableInterface`\n * Add argument `$filter` to `Profiler::find()` and `FileProfilerStorage::find()`\n * Add `ControllerResolver::allowControllers()` to define which callables are legit controllers when the `_check_controller_is_allowed` request attribute is set\n\n6.3\n---\n\n * Deprecate parameters `container.dumper.inline_factories` and `container.dumper.inline_class_loader`, use `.container.dumper.inline_factories` and `.container.dumper.inline_class_loader` instead\n * `FileProfilerStorage` removes profiles automatically after two days\n * Add `#[WithHttpStatus]` for defining status codes for exceptions\n * Use an instance of `Psr\\Clock\\ClockInterface` to generate the current date time in `DateTimeValueResolver`\n * Add `#[WithLogLevel]` for defining log levels for exceptions\n * Add `skip_response_headers` to the `HttpCache` options\n * Introduce targeted value resolvers with `#[ValueResolver]` and `#[AsTargetedValueResolver]`\n * Add `#[MapRequestPayload]` to map and validate request payload from `Request::getContent()` or `Request::$request->all()` to typed objects\n * Add `#[MapQueryString]` to map and validate request query string from `Request::$query->all()` to typed objects\n * Add `#[MapQueryParameter]` to map and validate individual query parameters to controller arguments\n * Collect data from every event dispatcher\n\n6.2\n---\n\n * Add constructor argument `bool $handleAllThrowable` to `HttpKernel`\n * Add `ControllerEvent::getAttributes()` to handle attributes on controllers\n * Add `#[Cache]` to describe the default HTTP cache headers on controllers\n * Add `absolute_uri` option to surrogate fragment renderers\n * Add `ValueResolverInterface` and deprecate `ArgumentValueResolverInterface`\n * Add argument `$reflector` to `ArgumentResolverInterface` and `ArgumentMetadataFactoryInterface`\n * Deprecate calling `ConfigDataCollector::setKernel()`, `RouterListener::setCurrentRequest()` without arguments\n\n6.1\n---\n\n * Add `BackedEnumValueResolver` to resolve backed enum cases from request attributes in controller arguments\n * Add `DateTimeValueResolver` to resolve request attributes into DateTime objects in controller arguments\n * Deprecate StreamedResponseListener, it's not needed anymore\n * Add `Profiler::isEnabled()` so collaborating collector services may elect to omit themselves\n * Add the `UidValueResolver` argument value resolver\n * Add `AbstractBundle` class for DI configuration/definition on a single file\n * Update the path of a bundle placed in the `src/` directory to the parent directory when `AbstractBundle` is used\n\n6.0\n---\n\n * Remove `ArgumentInterface`\n * Remove `ArgumentMetadata::getAttribute()`, use `getAttributes()` instead\n * Remove support for returning a `ContainerBuilder` from `KernelInterface::registerContainerConfiguration()`\n * Remove `KernelEvent::isMasterRequest()`, use `isMainRequest()` instead\n * Remove support for `service:action` syntax to reference controllers, use `serviceOrFqcn::method` instead\n\n5.4\n---\n\n * Add the ability to enable the profiler using a request query parameter, body parameter or attribute\n * Deprecate `AbstractTestSessionListener` and `TestSessionListener`, use `AbstractSessionListener` and `SessionListener` instead\n * Deprecate the `fileLinkFormat` parameter of `DebugHandlersListener`\n * Add support for configuring log level, and status code by exception class\n * Allow ignoring \"kernel.reset\" methods that don't exist with \"on_invalid\" attribute\n\n5.3\n---\n\n * Deprecate `ArgumentInterface`\n * Add `ArgumentMetadata::getAttributes()`\n * Deprecate `ArgumentMetadata::getAttribute()`, use `getAttributes()` instead\n * Mark the class `Symfony\\Component\\HttpKernel\\EventListener\\DebugHandlersListener` as internal\n * Deprecate returning a `ContainerBuilder` from `KernelInterface::registerContainerConfiguration()`\n * Deprecate `HttpKernelInterface::MASTER_REQUEST` and add `HttpKernelInterface::MAIN_REQUEST` as replacement\n * Deprecate `KernelEvent::isMasterRequest()` and add `isMainRequest()` as replacement\n * Add `#[AsController]` attribute for declaring standalone controllers on PHP 8\n * Add `FragmentUriGeneratorInterface` and `FragmentUriGenerator` to generate the URI of a fragment\n\n5.2.0\n-----\n\n * added session usage\n * made the public `http_cache` service handle requests when available\n * allowed enabling trusted hosts and proxies using new `kernel.trusted_hosts`,\n   `kernel.trusted_proxies` and `kernel.trusted_headers` parameters\n * content of request parameter `_password` is now also hidden\n   in the request profiler raw content section\n * Allowed adding attributes on controller arguments that will be passed to argument resolvers.\n * kernels implementing the `ExtensionInterface` will now be auto-registered to the container\n * added parameter `kernel.runtime_environment`, defined as `%env(default:kernel.environment:APP_RUNTIME_ENV)%`\n * do not set a default `Accept` HTTP header when using `HttpKernelBrowser`\n\n5.1.0\n-----\n\n * allowed to use a specific logger channel for deprecations\n * made `WarmableInterface::warmUp()` return a list of classes or files to preload on PHP 7.4+;\n   not returning an array is deprecated\n * made kernels implementing `WarmableInterface` be part of the cache warmup stage\n * deprecated support for `service:action` syntax to reference controllers, use `serviceOrFqcn::method` instead\n * allowed using public aliases to reference controllers\n * added session usage reporting when the `_stateless` attribute of the request is set to `true`\n * added `AbstractSessionListener::onSessionUsage()` to report when the session is used while a request is stateless\n\n5.0.0\n-----\n\n * removed support for getting the container from a non-booted kernel\n * removed the first and second constructor argument of `ConfigDataCollector`\n * removed `ConfigDataCollector::getApplicationName()`\n * removed `ConfigDataCollector::getApplicationVersion()`\n * removed support for `Symfony\\Component\\Templating\\EngineInterface` in `HIncludeFragmentRenderer`, use a `Twig\\Environment` only\n * removed `TranslatorListener` in favor of `LocaleAwareListener`\n * removed `getRootDir()` and `getName()` from `Kernel` and `KernelInterface`\n * removed `FilterControllerArgumentsEvent`, use `ControllerArgumentsEvent` instead\n * removed `FilterControllerEvent`, use `ControllerEvent` instead\n * removed `FilterResponseEvent`, use `ResponseEvent` instead\n * removed `GetResponseEvent`, use `RequestEvent` instead\n * removed `GetResponseForControllerResultEvent`, use `ViewEvent` instead\n * removed `GetResponseForExceptionEvent`, use `ExceptionEvent` instead\n * removed `PostResponseEvent`, use `TerminateEvent` instead\n * removed `SaveSessionListener` in favor of `AbstractSessionListener`\n * removed `Client`, use `HttpKernelBrowser` instead\n * added method `getProjectDir()` to `KernelInterface`\n * removed methods `serialize` and `unserialize` from `DataCollector`, store the serialized state in the data property instead\n * made `ProfilerStorageInterface` internal\n * removed the second and third argument of `KernelInterface::locateResource`\n * removed the second and third argument of `FileLocator::__construct`\n * removed loading resources from `%kernel.root_dir%/Resources` and `%kernel.root_dir%` as\n   fallback directories.\n * removed class `ExceptionListener`, use `ErrorListener` instead\n\n4.4.0\n-----\n\n * The `DebugHandlersListener` class has been marked as `final`\n * Added new Bundle directory convention consistent with standard skeletons\n * Deprecated the second and third argument of `KernelInterface::locateResource`\n * Deprecated the second and third argument of `FileLocator::__construct`\n * Deprecated loading resources from `%kernel.root_dir%/Resources` and `%kernel.root_dir%` as\n   fallback directories. Resources like service definitions are usually loaded relative to the\n   current directory or with a glob pattern. The fallback directories have never been advocated\n   so you likely do not use those in any app based on the SF Standard or Flex edition.\n * Marked all dispatched event classes as `@final`\n * Added `ErrorController` to enable the preview and error rendering mechanism\n * Getting the container from a non-booted kernel is deprecated.\n * Marked the `AjaxDataCollector`, `ConfigDataCollector`, `EventDataCollector`,\n   `ExceptionDataCollector`, `LoggerDataCollector`, `MemoryDataCollector`,\n   `RequestDataCollector` and `TimeDataCollector` classes as `@final`.\n * Marked the `RouterDataCollector::collect()` method as `@final`.\n * The `DataCollectorInterface::collect()` and `Profiler::collect()` methods third parameter signature\n   will be `\\Throwable $exception = null` instead of `\\Exception $exception = null` in Symfony 5.0.\n * Deprecated methods `ExceptionEvent::get/setException()`, use `get/setThrowable()` instead\n * Deprecated class `ExceptionListener`, use `ErrorListener` instead\n\n4.3.0\n-----\n\n * renamed `Client` to `HttpKernelBrowser`\n * `KernelInterface` doesn't extend `Serializable` anymore\n * deprecated the `Kernel::serialize()` and `unserialize()` methods\n * increased the priority of `Symfony\\Component\\HttpKernel\\EventListener\\AddRequestFormatsListener`\n * made `Symfony\\Component\\HttpKernel\\EventListener\\LocaleListener` set the default locale early\n * deprecated `TranslatorListener` in favor of `LocaleAwareListener`\n * added the registration of all `LocaleAwareInterface` implementations into the `LocaleAwareListener`\n * made `FileLinkFormatter` final and not implement `Serializable` anymore\n * the base `DataCollector` doesn't implement `Serializable` anymore, you should\n   store all the serialized state in the data property instead\n * `DumpDataCollector` has been marked as `final`\n * added an event listener to prevent search engines from indexing applications in debug mode.\n * renamed `FilterControllerArgumentsEvent` to `ControllerArgumentsEvent`\n * renamed `FilterControllerEvent` to `ControllerEvent`\n * renamed `FilterResponseEvent` to `ResponseEvent`\n * renamed `GetResponseEvent` to `RequestEvent`\n * renamed `GetResponseForControllerResultEvent` to `ViewEvent`\n * renamed `GetResponseForExceptionEvent` to `ExceptionEvent`\n * renamed `PostResponseEvent` to `TerminateEvent`\n * added `HttpClientKernel` for handling requests with an `HttpClientInterface` instance\n * added `trace_header` and `trace_level` configuration options to `HttpCache`\n\n4.2.0\n-----\n\n * deprecated `KernelInterface::getRootDir()` and the `kernel.root_dir` parameter\n * deprecated `KernelInterface::getName()` and the `kernel.name` parameter\n * deprecated the first and second constructor argument of `ConfigDataCollector`\n * deprecated `ConfigDataCollector::getApplicationName()`\n * deprecated `ConfigDataCollector::getApplicationVersion()`\n\n4.1.0\n-----\n\n * added orphaned events support to `EventDataCollector`\n * `ExceptionListener` now logs exceptions at priority `0` (previously logged at `-128`)\n * 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.\n * Added the ability to profile individual argument value resolvers via the\n   `Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\TraceableValueResolver`\n\n4.0.0\n-----\n\n * removed the `DataCollector::varToString()` method, use `DataCollector::cloneVar()`\n   instead\n * using the `DataCollector::cloneVar()` method requires the VarDumper component\n * removed the `ValueExporter` class\n * removed `ControllerResolverInterface::getArguments()`\n * removed `TraceableControllerResolver::getArguments()`\n * removed `ControllerResolver::getArguments()` and the ability to resolve arguments\n * removed the `argument_resolver` service dependency from the `debug.controller_resolver`\n * removed `LazyLoadingFragmentHandler::addRendererService()`\n * removed `Psr6CacheClearer::addPool()`\n * removed `Extension::addClassesToCompile()` and `Extension::getClassesToCompile()`\n * removed `Kernel::loadClassCache()`, `Kernel::doLoadClassCache()`, `Kernel::setClassCache()`,\n   and `Kernel::getEnvParameters()`\n * support for the `X-Status-Code` when handling exceptions in the `HttpKernel`\n   has been dropped, use the `HttpKernel::allowCustomResponseCode()` method\n   instead\n * removed convention-based commands registration\n * removed the `ChainCacheClearer::add()` method\n * removed the `CacheaWarmerAggregate::add()` and `setWarmers()` methods\n * made `CacheWarmerAggregate` and `ChainCacheClearer` classes final\n\n3.4.0\n-----\n\n * added a minimalist PSR-3 `Logger` class that writes in `stderr`\n * made kernels implementing `CompilerPassInterface` able to process the container\n * deprecated bundle inheritance\n * added `RebootableInterface` and implemented it in `Kernel`\n * deprecated commands auto registration\n * deprecated `EnvParametersResource`\n * added `Symfony\\Component\\HttpKernel\\Client::catchExceptions()`\n * deprecated the `ChainCacheClearer::add()` method\n * deprecated the `CacheaWarmerAggregate::add()` and `setWarmers()` methods\n * made `CacheWarmerAggregate` and `ChainCacheClearer` classes final\n * added the possibility to reset the profiler to its initial state\n * deprecated data collectors without a `reset()` method\n * deprecated implementing `DebugLoggerInterface` without a `clear()` method\n\n3.3.0\n-----\n\n * added `kernel.project_dir` and `Kernel::getProjectDir()`\n * deprecated `kernel.root_dir` and `Kernel::getRootDir()`\n * deprecated `Kernel::getEnvParameters()`\n * deprecated the special `SYMFONY__` environment variables\n * added the possibility to change the query string parameter used by `UriSigner`\n * deprecated `LazyLoadingFragmentHandler::addRendererService()`\n * deprecated `Extension::addClassesToCompile()` and `Extension::getClassesToCompile()`\n * deprecated `Psr6CacheClearer::addPool()`\n\n3.2.0\n-----\n\n * deprecated `DataCollector::varToString()`, use `cloneVar()` instead\n * changed surrogate capability name in `AbstractSurrogate::addSurrogateCapability` to 'symfony'\n * Added `ControllerArgumentValueResolverPass`\n\n3.1.0\n-----\n * deprecated passing objects as URI attributes to the ESI and SSI renderers\n * deprecated `ControllerResolver::getArguments()`\n * added `Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolverInterface`\n * added `Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolverInterface` as argument to `HttpKernel`\n * added `Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver`\n * added `Symfony\\Component\\HttpKernel\\DataCollector\\RequestDataCollector::getMethod()`\n * added `Symfony\\Component\\HttpKernel\\DataCollector\\RequestDataCollector::getRedirect()`\n * added the `kernel.controller_arguments` event, triggered after controller arguments have been resolved\n\n3.0.0\n-----\n\n * removed `Symfony\\Component\\HttpKernel\\Kernel::init()`\n * removed `Symfony\\Component\\HttpKernel\\Kernel::isClassInActiveBundle()` and `Symfony\\Component\\HttpKernel\\KernelInterface::isClassInActiveBundle()`\n * removed `Symfony\\Component\\HttpKernel\\Debug\\TraceableEventDispatcher::setProfiler()`\n * removed `Symfony\\Component\\HttpKernel\\EventListener\\FragmentListener::getLocalIpAddresses()`\n * removed `Symfony\\Component\\HttpKernel\\EventListener\\LocaleListener::setRequest()`\n * removed `Symfony\\Component\\HttpKernel\\EventListener\\RouterListener::setRequest()`\n * removed `Symfony\\Component\\HttpKernel\\EventListener\\ProfilerListener::onKernelRequest()`\n * removed `Symfony\\Component\\HttpKernel\\Fragment\\FragmentHandler::setRequest()`\n * removed `Symfony\\Component\\HttpKernel\\HttpCache\\Esi::hasSurrogateEsiCapability()`\n * removed `Symfony\\Component\\HttpKernel\\HttpCache\\Esi::addSurrogateEsiCapability()`\n * removed `Symfony\\Component\\HttpKernel\\HttpCache\\Esi::needsEsiParsing()`\n * removed `Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache::getEsi()`\n * removed `Symfony\\Component\\HttpKernel\\DependencyInjection\\ContainerAwareHttpKernel`\n * removed `Symfony\\Component\\HttpKernel\\DependencyInjection\\RegisterListenersPass`\n * removed `Symfony\\Component\\HttpKernel\\EventListener\\ErrorsLoggerListener`\n * removed `Symfony\\Component\\HttpKernel\\EventListener\\EsiListener`\n * removed `Symfony\\Component\\HttpKernel\\HttpCache\\EsiResponseCacheStrategy`\n * removed `Symfony\\Component\\HttpKernel\\HttpCache\\EsiResponseCacheStrategyInterface`\n * removed `Symfony\\Component\\HttpKernel\\Log\\LoggerInterface`\n * removed `Symfony\\Component\\HttpKernel\\Log\\NullLogger`\n * removed `Symfony\\Component\\HttpKernel\\Profiler::import()`\n * removed `Symfony\\Component\\HttpKernel\\Profiler::export()`\n\n2.8.0\n-----\n\n * deprecated `Profiler::import` and `Profiler::export`\n\n2.7.0\n-----\n\n * added the HTTP status code to profiles\n\n2.6.0\n-----\n\n * deprecated `Symfony\\Component\\HttpKernel\\EventListener\\ErrorsLoggerListener`, use `Symfony\\Component\\HttpKernel\\EventListener\\DebugHandlersListener` instead\n * deprecated unused method `Symfony\\Component\\HttpKernel\\Kernel::isClassInActiveBundle` and `Symfony\\Component\\HttpKernel\\KernelInterface::isClassInActiveBundle`\n\n2.5.0\n-----\n\n * deprecated `Symfony\\Component\\HttpKernel\\DependencyInjection\\RegisterListenersPass`, use `Symfony\\Component\\EventDispatcher\\DependencyInjection\\RegisterListenersPass` instead\n\n2.4.0\n-----\n\n * added event listeners for the session\n * added the KernelEvents::FINISH_REQUEST event\n\n2.3.0\n-----\n\n * [BC BREAK] renamed `Symfony\\Component\\HttpKernel\\EventListener\\DeprecationLoggerListener` to `Symfony\\Component\\HttpKernel\\EventListener\\ErrorsLoggerListener` and changed its constructor\n * deprecated `Symfony\\Component\\HttpKernel\\Debug\\ErrorHandler`, `Symfony\\Component\\HttpKernel\\Debug\\ExceptionHandler`,\n   `Symfony\\Component\\HttpKernel\\Exception\\FatalErrorException` and `Symfony\\Component\\HttpKernel\\Exception\\FlattenException`\n * deprecated `Symfony\\Component\\HttpKernel\\Kernel::init()`\n * added the possibility to specify an id an extra attributes to hinclude tags\n * added the collect of data if a controller is a Closure in the Request collector\n * pass exceptions from the ExceptionListener to the logger using the logging context to allow for more\n   detailed messages\n\n2.2.0\n-----\n\n * [BC BREAK] the path info for sub-request is now always _fragment (or whatever you configured instead of the default)\n * added Symfony\\Component\\HttpKernel\\EventListener\\FragmentListener\n * added Symfony\\Component\\HttpKernel\\UriSigner\n * added Symfony\\Component\\HttpKernel\\FragmentRenderer and rendering strategies (in Symfony\\Component\\HttpKernel\\Fragment\\FragmentRendererInterface)\n * added Symfony\\Component\\HttpKernel\\DependencyInjection\\ContainerAwareHttpKernel\n * added ControllerReference to create reference of Controllers (used in the FragmentRenderer class)\n * [BC BREAK] renamed TimeDataCollector::getTotalTime() to\n   TimeDataCollector::getDuration()\n * updated the MemoryDataCollector to include the memory used in the\n   kernel.terminate event listeners\n * moved the Stopwatch classes to a new component\n * added TraceableControllerResolver\n * added TraceableEventDispatcher (removed ContainerAwareTraceableEventDispatcher)\n * added support for WinCache opcode cache in ConfigDataCollector\n\n2.1.0\n-----\n\n * [BC BREAK] the charset is now configured via the Kernel::getCharset() method\n * [BC BREAK] the current locale for the user is not stored anymore in the session\n * added the HTTP method to the profiler storage\n * updated all listeners to implement EventSubscriberInterface\n * added TimeDataCollector\n * added ContainerAwareTraceableEventDispatcher\n * moved TraceableEventDispatcherInterface to the EventDispatcher component\n * added RouterListener, LocaleListener, and StreamedResponseListener\n * added CacheClearerInterface (and ChainCacheClearer)\n * added a kernel.terminate event (via TerminableInterface and PostResponseEvent)\n * added a Stopwatch class\n * added WarmableInterface\n * improved extensibility between bundles\n * added profiler storages for Memcache(d), File-based, MongoDB, Redis\n * moved Filesystem class to its own component\n"
  },
  {
    "path": "CacheClearer/CacheClearerInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\CacheClearer;\n\n/**\n * CacheClearerInterface.\n *\n * @author Dustin Dobervich <ddobervich@gmail.com>\n */\ninterface CacheClearerInterface\n{\n    /**\n     * Clears any caches necessary.\n     */\n    public function clear(string $cacheDir): void;\n}\n"
  },
  {
    "path": "CacheClearer/ChainCacheClearer.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\CacheClearer;\n\n/**\n * ChainCacheClearer.\n *\n * @author Dustin Dobervich <ddobervich@gmail.com>\n *\n * @final\n */\nclass ChainCacheClearer implements CacheClearerInterface\n{\n    /**\n     * @param iterable<mixed, CacheClearerInterface> $clearers\n     */\n    public function __construct(\n        private iterable $clearers = [],\n    ) {\n    }\n\n    public function clear(string $cacheDir): void\n    {\n        foreach ($this->clearers as $clearer) {\n            $clearer->clear($cacheDir);\n        }\n    }\n}\n"
  },
  {
    "path": "CacheClearer/Psr6CacheClearer.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\CacheClearer;\n\nuse Psr\\Cache\\CacheItemPoolInterface;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass Psr6CacheClearer implements CacheClearerInterface\n{\n    private array $pools = [];\n\n    /**\n     * @param array<string, CacheItemPoolInterface> $pools\n     */\n    public function __construct(array $pools = [])\n    {\n        $this->pools = $pools;\n    }\n\n    public function hasPool(string $name): bool\n    {\n        return isset($this->pools[$name]);\n    }\n\n    /**\n     * @throws \\InvalidArgumentException If the cache pool with the given name does not exist\n     */\n    public function getPool(string $name): CacheItemPoolInterface\n    {\n        if (!$this->hasPool($name)) {\n            throw new \\InvalidArgumentException(\\sprintf('Cache pool not found: \"%s\".', $name));\n        }\n\n        return $this->pools[$name];\n    }\n\n    /**\n     * @throws \\InvalidArgumentException If the cache pool with the given name does not exist\n     */\n    public function clearPool(string $name): bool\n    {\n        if (!isset($this->pools[$name])) {\n            throw new \\InvalidArgumentException(\\sprintf('Cache pool not found: \"%s\".', $name));\n        }\n\n        return $this->pools[$name]->clear();\n    }\n\n    public function clear(string $cacheDir): void\n    {\n        foreach ($this->pools as $pool) {\n            $pool->clear();\n        }\n    }\n}\n"
  },
  {
    "path": "CacheWarmer/CacheWarmer.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\CacheWarmer;\n\n/**\n * Abstract cache warmer that knows how to write a file to the cache.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nabstract class CacheWarmer implements CacheWarmerInterface\n{\n    protected function writeCacheFile(string $file, $content): void\n    {\n        $tmpFile = @tempnam(\\dirname($file), basename($file));\n        if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $file)) {\n            @chmod($file, 0o666 & ~umask());\n\n            return;\n        }\n\n        throw new \\RuntimeException(\\sprintf('Failed to write cache file \"%s\".', $file));\n    }\n}\n"
  },
  {
    "path": "CacheWarmer/CacheWarmerAggregate.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\CacheWarmer;\n\nuse Symfony\\Component\\Console\\Style\\SymfonyStyle;\n\n/**\n * Aggregates several cache warmers into a single one.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @final\n */\nclass CacheWarmerAggregate implements CacheWarmerInterface\n{\n    private bool $optionalsEnabled = false;\n    private bool $onlyOptionalsEnabled = false;\n\n    /**\n     * @param iterable<mixed, CacheWarmerInterface> $warmers\n     */\n    public function __construct(\n        private iterable $warmers = [],\n        private bool $debug = false,\n        private ?string $deprecationLogsFilepath = null,\n    ) {\n    }\n\n    public function enableOptionalWarmers(): void\n    {\n        $this->optionalsEnabled = true;\n    }\n\n    public function enableOnlyOptionalWarmers(): void\n    {\n        $this->onlyOptionalsEnabled = $this->optionalsEnabled = true;\n    }\n\n    public function warmUp(string $cacheDir, ?string $buildDir = null, ?SymfonyStyle $io = null): array\n    {\n        if ($collectDeprecations = $this->debug && !\\defined('PHPUNIT_COMPOSER_INSTALL')) {\n            $collectedLogs = [];\n            $previousHandler = set_error_handler(static function ($type, $message, $file, $line) use (&$collectedLogs, &$previousHandler) {\n                if (\\E_USER_DEPRECATED !== $type && \\E_DEPRECATED !== $type) {\n                    return $previousHandler ? $previousHandler($type, $message, $file, $line) : false;\n                }\n\n                if (isset($collectedLogs[$message])) {\n                    ++$collectedLogs[$message]['count'];\n\n                    return null;\n                }\n\n                $backtrace = debug_backtrace(\\DEBUG_BACKTRACE_IGNORE_ARGS, 3);\n                // Clean the trace by removing first frames added by the error handler itself.\n                for ($i = 0; isset($backtrace[$i]); ++$i) {\n                    if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) {\n                        $backtrace = \\array_slice($backtrace, 1 + $i);\n                        break;\n                    }\n                }\n\n                $collectedLogs[$message] = [\n                    'type' => $type,\n                    'message' => $message,\n                    'file' => $file,\n                    'line' => $line,\n                    'trace' => $backtrace,\n                    'count' => 1,\n                ];\n\n                return null;\n            });\n        }\n\n        $preload = [];\n        try {\n            foreach ($this->warmers as $warmer) {\n                if (!$this->optionalsEnabled && $warmer->isOptional()) {\n                    continue;\n                }\n                if ($this->onlyOptionalsEnabled && !$warmer->isOptional()) {\n                    continue;\n                }\n\n                $start = microtime(true);\n                foreach ($warmer->warmUp($cacheDir, $buildDir) as $item) {\n                    if (is_dir($item) || (str_starts_with($item, \\dirname($cacheDir)) && !is_file($item)) || ($buildDir && str_starts_with($item, \\dirname($buildDir)) && !is_file($item))) {\n                        throw new \\LogicException(\\sprintf('\"%s::warmUp()\" should return a list of files or classes but \"%s\" is none of them.', $warmer::class, $item));\n                    }\n                    $preload[] = $item;\n                }\n\n                if ($io?->isDebug()) {\n                    $io->info(\\sprintf('\"%s\" completed in %0.2fms.', $warmer::class, 1000 * (microtime(true) - $start)));\n                }\n            }\n        } finally {\n            if ($collectDeprecations) {\n                restore_error_handler();\n\n                if (is_file($this->deprecationLogsFilepath)) {\n                    $previousLogs = unserialize(file_get_contents($this->deprecationLogsFilepath));\n                    if (\\is_array($previousLogs)) {\n                        $collectedLogs = array_merge($previousLogs, $collectedLogs);\n                    }\n                }\n\n                file_put_contents($this->deprecationLogsFilepath, serialize(array_values($collectedLogs)));\n            }\n        }\n\n        return array_values(array_unique($preload));\n    }\n\n    public function isOptional(): bool\n    {\n        return false;\n    }\n}\n"
  },
  {
    "path": "CacheWarmer/CacheWarmerInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\CacheWarmer;\n\n/**\n * Interface for classes able to warm up the cache.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface CacheWarmerInterface extends WarmableInterface\n{\n    /**\n     * Checks whether this warmer is optional or not.\n     *\n     * Optional warmers can be ignored on certain conditions.\n     *\n     * A warmer should return true if the cache can be\n     * generated incrementally and on-demand.\n     */\n    public function isOptional(): bool;\n}\n"
  },
  {
    "path": "CacheWarmer/WarmableInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\CacheWarmer;\n\n/**\n * Interface for classes that support warming their cache.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface WarmableInterface\n{\n    /**\n     * Warms up the cache.\n     *\n     * @param string      $cacheDir Where warm-up artifacts should be stored\n     * @param string|null $buildDir Where read-only artifacts should go; null when called after compile-time\n     *\n     * @return string[] A list of classes or files to preload\n     */\n    public function warmUp(string $cacheDir, ?string $buildDir = null): array;\n}\n"
  },
  {
    "path": "Config/FileLocator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Config;\n\nuse Symfony\\Component\\Config\\FileLocator as BaseFileLocator;\nuse Symfony\\Component\\HttpKernel\\KernelInterface;\n\n/**\n * FileLocator uses the KernelInterface to locate resources in bundles.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass FileLocator extends BaseFileLocator\n{\n    public function __construct(\n        private KernelInterface $kernel,\n    ) {\n        parent::__construct();\n    }\n\n    public function locate(string $file, ?string $currentPath = null, bool $first = true): string|array\n    {\n        if (isset($file[0]) && '@' === $file[0]) {\n            $resource = $this->kernel->locateResource($file);\n\n            return $first ? $resource : [$resource];\n        }\n\n        return parent::locate($file, $currentPath, $first);\n    }\n}\n"
  },
  {
    "path": "Controller/ArgumentResolver/BackedEnumValueResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;\n\n/**\n * Attempt to resolve backed enum cases from request attributes, for a route path parameter,\n * leading to a 404 Not Found if the attribute value isn't a valid backing value for the enum type.\n *\n * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>\n */\nfinal class BackedEnumValueResolver implements ValueResolverInterface\n{\n    public function resolve(Request $request, ArgumentMetadata $argument): iterable\n    {\n        if (!is_subclass_of($argument->getType(), \\BackedEnum::class)) {\n            return [];\n        }\n\n        if ($argument->isVariadic()) {\n            // only target route path parameters, which cannot be variadic.\n            return [];\n        }\n\n        $name = $argument->getName();\n\n        // do not support if no value can be resolved at all\n        // letting the \\Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\DefaultValueResolver be used\n        // or \\Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver fail with a meaningful error.\n        if (!$request->attributes->has($name)) {\n            return [];\n        }\n\n        if (null === $value = $request->attributes->get($name)) {\n            return [null];\n        }\n\n        if ($value instanceof \\BackedEnum) {\n            return [$value];\n        }\n\n        /** @var class-string<\\BackedEnum> $type */\n        $type = $argument->getType();\n\n        if (!\\is_int($value) && !\\is_string($value)) {\n            throw new NotFoundHttpException(\\sprintf('Could not resolve the \"%s $%s\" controller argument: expecting an int or string, got \"%s\".', $type, $name, get_debug_type($value)));\n        }\n\n        try {\n            return [$type::from($value)];\n        } catch (\\ValueError|\\TypeError $e) {\n            throw new NotFoundHttpException(\\sprintf('Could not resolve the \"%s $%s\" controller argument: ', $type, $name).$e->getMessage(), $e);\n        }\n    }\n}\n"
  },
  {
    "path": "Controller/ArgumentResolver/DateTimeValueResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\n\nuse Psr\\Clock\\ClockInterface;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Attribute\\MapDateTime;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;\n\n/**\n * Convert DateTime instances from request attribute variable.\n *\n * @author Benjamin Eberlei <kontakt@beberlei.de>\n * @author Tim Goudriaan <tim@codedmonkey.com>\n */\nfinal class DateTimeValueResolver implements ValueResolverInterface\n{\n    public function __construct(\n        private readonly ?ClockInterface $clock = null,\n    ) {\n    }\n\n    public function resolve(Request $request, ArgumentMetadata $argument): array\n    {\n        if (!is_a($argument->getType(), \\DateTimeInterface::class, true) || !$request->attributes->has($argument->getName())) {\n            return [];\n        }\n\n        $value = $request->attributes->get($argument->getName());\n        $class = \\DateTimeInterface::class === $argument->getType() ? \\DateTimeImmutable::class : $argument->getType();\n\n        if (!$value) {\n            if ($argument->isNullable()) {\n                return [null];\n            }\n            if (!$this->clock) {\n                return [new $class()];\n            }\n            $value = $this->clock->now();\n        }\n\n        if ($value instanceof \\DateTimeInterface) {\n            return [$value instanceof $class ? $value : $class::createFromInterface($value)];\n        }\n\n        $format = null;\n\n        if ($attributes = $argument->getAttributes(MapDateTime::class, ArgumentMetadata::IS_INSTANCEOF)) {\n            $attribute = $attributes[0];\n            $format = $attribute->format;\n        }\n\n        if (null !== $format) {\n            $date = $class::createFromFormat($format, $value, $this->clock?->now()->getTimeZone());\n\n            if (($class::getLastErrors() ?: ['warning_count' => 0])['warning_count']) {\n                $date = false;\n            }\n        } else {\n            if (false !== filter_var($value, \\FILTER_VALIDATE_INT, ['options' => ['min_range' => 0]])) {\n                $value = '@'.$value;\n            }\n            try {\n                $date = new $class($value, $this->clock?->now()->getTimeZone());\n            } catch (\\Exception) {\n                $date = false;\n            }\n        }\n\n        if (!$date) {\n            throw new NotFoundHttpException(\\sprintf('Invalid date given for parameter \"%s\".', $argument->getName()));\n        }\n\n        return [$date];\n    }\n}\n"
  },
  {
    "path": "Controller/ArgumentResolver/DefaultValueResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\n\n/**\n * Yields the default value defined in the action signature when no value has been given.\n *\n * @author Iltar van der Berg <kjarli@gmail.com>\n */\nfinal class DefaultValueResolver implements ValueResolverInterface\n{\n    public function resolve(Request $request, ArgumentMetadata $argument): array\n    {\n        if ($argument->hasDefaultValue()) {\n            return [$argument->getDefaultValue()];\n        }\n\n        if (null !== $argument->getType() && $argument->isNullable() && !$argument->isVariadic()) {\n            return [null];\n        }\n\n        return [];\n    }\n}\n"
  },
  {
    "path": "Controller/ArgumentResolver/NotTaggedControllerValueResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\n\nuse Psr\\Container\\ContainerInterface;\nuse Symfony\\Component\\DependencyInjection\\Exception\\RuntimeException;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\n\n/**\n * Provides an intuitive error message when controller fails because it is not registered as a service.\n *\n * @author Simeon Kolev <simeon.kolev9@gmail.com>\n */\nfinal class NotTaggedControllerValueResolver implements ValueResolverInterface\n{\n    public function __construct(\n        private ContainerInterface $container,\n    ) {\n    }\n\n    public function resolve(Request $request, ArgumentMetadata $argument): array\n    {\n        $controller = $request->attributes->get('_controller');\n\n        if (\\is_array($controller) && \\is_callable($controller, true) && \\is_string($controller[0])) {\n            $controller = $controller[0].'::'.$controller[1];\n        } elseif (!\\is_string($controller) || '' === $controller) {\n            return [];\n        }\n\n        if ('\\\\' === $controller[0]) {\n            $controller = ltrim($controller, '\\\\');\n        }\n\n        if (!$this->container->has($controller)) {\n            $controller = (false !== $i = strrpos($controller, ':'))\n                ? substr($controller, 0, $i).strtolower(substr($controller, $i))\n                : $controller.'::__invoke';\n        }\n\n        if ($this->container->has($controller)) {\n            return [];\n        }\n\n        $what = \\sprintf('argument $%s of \"%s()\"', $argument->getName(), $controller);\n        $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);\n\n        throw new RuntimeException($message);\n    }\n}\n"
  },
  {
    "path": "Controller/ArgumentResolver/QueryParameterValueResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Attribute\\MapQueryParameter;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\Uid\\AbstractUid;\n\n/**\n * Resolve arguments of type: array, string, int, float, bool, \\BackedEnum from query parameters.\n *\n * @author Ruud Kamphuis <ruud@ticketswap.com>\n * @author Nicolas Grekas <p@tchwork.com>\n * @author Mateusz Anders <anders_mateusz@outlook.com>\n * @author Ionut Enache <i.ovidiuenache@yahoo.com>\n */\nfinal class QueryParameterValueResolver implements ValueResolverInterface\n{\n    public function resolve(Request $request, ArgumentMetadata $argument): array\n    {\n        if (!$attribute = $argument->getAttributesOfType(MapQueryParameter::class)[0] ?? null) {\n            return [];\n        }\n\n        $name = $attribute->name ?? $argument->getName();\n        $validationFailedCode = $attribute->validationFailedStatusCode;\n\n        if (!$request->query->has($name)) {\n            if ($argument->isNullable() || $argument->hasDefaultValue()) {\n                return [];\n            }\n\n            throw HttpException::fromStatusCode($validationFailedCode, \\sprintf('Missing query parameter \"%s\".', $name));\n        }\n\n        $value = $request->query->all()[$name];\n        $type = $argument->getType();\n\n        if (null === $attribute->filter && 'array' === $type) {\n            if (!$argument->isVariadic()) {\n                return [(array) $value];\n            }\n\n            $filtered = array_values(array_filter((array) $value, \\is_array(...)));\n\n            if ($filtered !== $value && !($attribute->flags & \\FILTER_NULL_ON_FAILURE)) {\n                throw HttpException::fromStatusCode($validationFailedCode, \\sprintf('Invalid query parameter \"%s\".', $name));\n            }\n\n            return $filtered;\n        }\n\n        $options = [\n            'flags' => $attribute->flags | \\FILTER_NULL_ON_FAILURE,\n            'options' => $attribute->options,\n        ];\n\n        if ('array' === $type || $argument->isVariadic()) {\n            $value = (array) $value;\n            $options['flags'] |= \\FILTER_REQUIRE_ARRAY;\n        } else {\n            $options['flags'] |= \\FILTER_REQUIRE_SCALAR;\n        }\n\n        $uidType = null;\n        if (is_subclass_of($type, AbstractUid::class)) {\n            $uidType = $type;\n            $type = 'uid';\n        }\n\n        $enumType = null;\n        $filter = match ($type) {\n            'array' => \\FILTER_DEFAULT,\n            'string' => isset($attribute->options['regexp']) ? \\FILTER_VALIDATE_REGEXP : \\FILTER_DEFAULT,\n            'int' => \\FILTER_VALIDATE_INT,\n            'float' => \\FILTER_VALIDATE_FLOAT,\n            'bool' => \\FILTER_VALIDATE_BOOL,\n            'uid' => \\FILTER_DEFAULT,\n            default => match ($enumType = is_subclass_of($type, \\BackedEnum::class) ? (new \\ReflectionEnum($type))->getBackingType()->getName() : null) {\n                'int' => \\FILTER_VALIDATE_INT,\n                'string' => \\FILTER_DEFAULT,\n                default => throw new \\LogicException(\\sprintf('#[MapQueryParameter] cannot be used on controller argument \"%s$%s\" of type \"%s\"; one of array, string, int, float, bool, uid or \\BackedEnum should be used.', $argument->isVariadic() ? '...' : '', $argument->getName(), $type ?? 'mixed')),\n            },\n        };\n\n        $value = filter_var($value, $attribute->filter ?? $filter, $options);\n\n        if (null !== $enumType && null !== $value) {\n            $enumFrom = static function ($value) use ($type) {\n                if (!\\is_string($value) && !\\is_int($value)) {\n                    return null;\n                }\n\n                try {\n                    return $type::from($value);\n                } catch (\\ValueError) {\n                    return null;\n                }\n            };\n\n            $value = \\is_array($value) ? array_map($enumFrom, $value) : $enumFrom($value);\n        }\n\n        if (null !== $uidType) {\n            $value = \\is_array($value) ? array_map([$uidType, 'fromString'], $value) : $uidType::fromString($value);\n        }\n\n        if (null === $value && !($attribute->flags & \\FILTER_NULL_ON_FAILURE)) {\n            throw HttpException::fromStatusCode($validationFailedCode, \\sprintf('Invalid query parameter \"%s\".', $name));\n        }\n\n        if (!\\is_array($value)) {\n            return [$value];\n        }\n\n        $filtered = array_filter($value, static fn ($v) => null !== $v);\n\n        if ($argument->isVariadic()) {\n            $filtered = array_values($filtered);\n        }\n\n        if ($filtered !== $value && !($attribute->flags & \\FILTER_NULL_ON_FAILURE)) {\n            throw HttpException::fromStatusCode($validationFailedCode, \\sprintf('Invalid query parameter \"%s\".', $name));\n        }\n\n        return $argument->isVariadic() ? $filtered : [$filtered];\n    }\n}\n"
  },
  {
    "path": "Controller/ArgumentResolver/RequestAttributeValueResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;\n\n/**\n * Yields a non-variadic argument's value from the request attributes.\n *\n * @author Iltar van der Berg <kjarli@gmail.com>\n */\nfinal class RequestAttributeValueResolver implements ValueResolverInterface\n{\n    public function resolve(Request $request, ArgumentMetadata $argument): array\n    {\n        if ($argument->isVariadic()) {\n            return [];\n        }\n\n        $name = $argument->getName();\n        if (!$request->attributes->has($name)) {\n            return [];\n        }\n\n        $value = $request->attributes->get($name);\n\n        if (null === $value && $argument->isNullable()) {\n            return [null];\n        }\n\n        $type = $argument->getType();\n\n        // Skip when no type declaration or complex types; fall back to other resolvers/defaults\n        if (null === $type || str_contains($type, '|') || str_contains($type, '&')) {\n            return [$value];\n        }\n\n        if ('string' === $type) {\n            if (!\\is_scalar($value) && !$value instanceof \\Stringable) {\n                throw new NotFoundHttpException(\\sprintf('The value for the \"%s\" route parameter is invalid.', $name));\n            }\n\n            $value = (string) $value;\n        } elseif ($filter = match ($type) {\n            'int' => \\FILTER_VALIDATE_INT,\n            'float' => \\FILTER_VALIDATE_FLOAT,\n            'bool' => \\FILTER_VALIDATE_BOOL,\n            default => null,\n        }) {\n            if (null === $value = $request->attributes->filter($name, null, $filter, ['flags' => \\FILTER_NULL_ON_FAILURE | \\FILTER_REQUIRE_SCALAR])) {\n                throw new NotFoundHttpException(\\sprintf('The value for the \"%s\" route parameter is invalid.', $name));\n            }\n        }\n\n        return [$value];\n    }\n}\n"
  },
  {
    "path": "Controller/ArgumentResolver/RequestHeaderValueResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\n\nuse Symfony\\Component\\HttpFoundation\\AcceptHeader;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Attribute\\MapRequestHeader;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\n\nfinal class RequestHeaderValueResolver implements ValueResolverInterface\n{\n    public function resolve(Request $request, ArgumentMetadata $argument): array\n    {\n        if (!$attribute = $argument->getAttributesOfType(MapRequestHeader::class)[0] ?? null) {\n            return [];\n        }\n\n        $type = $argument->getType();\n\n        if (!\\in_array($type, ['string', 'array', AcceptHeader::class])) {\n            throw new \\LogicException(\\sprintf('Could not resolve the argument typed \"%s\". Valid types are \"array\", \"string\" or \"%s\".', $type, AcceptHeader::class));\n        }\n\n        $name = $attribute->name ?? strtolower(preg_replace('/[a-z]\\K[A-Z]/', '-$0', $argument->getName()));\n        $value = null;\n\n        if ($request->headers->has($name)) {\n            $value = match ($type) {\n                'string' => $request->headers->get($name),\n                'array' => match (strtolower($name)) {\n                    'accept' => $request->getAcceptableContentTypes(),\n                    'accept-charset' => $request->getCharsets(),\n                    'accept-language' => $request->getLanguages(),\n                    'accept-encoding' => $request->getEncodings(),\n                    default => $request->headers->all($name),\n                },\n                AcceptHeader::class => AcceptHeader::fromString($request->headers->get($name)),\n            };\n        } elseif ($argument->hasDefaultValue()) {\n            $value = $argument->getDefaultValue();\n        }\n\n        if (null === $value && 'array' === $type) {\n            $value = [];\n        }\n\n        if (null === $value && !$argument->isNullable()) {\n            throw HttpException::fromStatusCode($attribute->validationFailedStatusCode, \\sprintf('Missing header \"%s\".', $name));\n        }\n\n        return [$value];\n    }\n}\n"
  },
  {
    "path": "Controller/ArgumentResolver/RequestPayloadValueResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\n\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\ExpressionLanguage\\Expression;\nuse Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage;\nuse Symfony\\Component\\HttpFoundation\\File\\UploadedFile;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Attribute\\MapQueryString;\nuse Symfony\\Component\\HttpKernel\\Attribute\\MapRequestPayload;\nuse Symfony\\Component\\HttpKernel\\Attribute\\MapUploadedFile;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsEvent;\nuse Symfony\\Component\\HttpKernel\\Exception\\BadRequestHttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\NearMissValueResolverException;\nuse Symfony\\Component\\HttpKernel\\Exception\\UnsupportedMediaTypeHttpException;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\nuse Symfony\\Component\\Serializer\\Exception\\InvalidArgumentException as SerializerInvalidArgumentException;\nuse Symfony\\Component\\Serializer\\Exception\\NotEncodableValueException;\nuse Symfony\\Component\\Serializer\\Exception\\PartialDenormalizationException;\nuse Symfony\\Component\\Serializer\\Exception\\UnexpectedPropertyException;\nuse Symfony\\Component\\Serializer\\Exception\\UnsupportedFormatException;\nuse Symfony\\Component\\Serializer\\Normalizer\\DenormalizerInterface;\nuse Symfony\\Component\\Serializer\\SerializerInterface;\nuse Symfony\\Component\\Validator\\Constraints as Assert;\nuse Symfony\\Component\\Validator\\Constraints\\GroupSequence;\nuse Symfony\\Component\\Validator\\ConstraintViolation;\nuse Symfony\\Component\\Validator\\ConstraintViolationList;\nuse Symfony\\Component\\Validator\\Exception\\ValidationFailedException;\nuse Symfony\\Component\\Validator\\Validator\\ValidatorInterface;\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\n/**\n * @author Konstantin Myakshin <molodchick@gmail.com>\n *\n * @psalm-type GroupResolver = \\Closure(array<string, mixed>, Request, ?object):string|GroupSequence|array<string>\n *\n * @final\n */\nclass RequestPayloadValueResolver implements ValueResolverInterface, EventSubscriberInterface\n{\n    /**\n     * @see DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS\n     */\n    private const CONTEXT_DENORMALIZE = [\n        'collect_denormalization_errors' => true,\n    ];\n\n    /**\n     * @see DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS\n     */\n    private const CONTEXT_DESERIALIZE = [\n        'collect_denormalization_errors' => true,\n    ];\n\n    public function __construct(\n        private readonly SerializerInterface&DenormalizerInterface $serializer,\n        private readonly ?ValidatorInterface $validator = null,\n        private readonly ?TranslatorInterface $translator = null,\n        private string $translationDomain = 'validators',\n        private ?ExpressionLanguage $expressionLanguage = null,\n    ) {\n    }\n\n    public function resolve(Request $request, ArgumentMetadata $argument): iterable\n    {\n        $attribute = $argument->getAttributesOfType(MapQueryString::class, ArgumentMetadata::IS_INSTANCEOF)[0]\n            ?? $argument->getAttributesOfType(MapRequestPayload::class, ArgumentMetadata::IS_INSTANCEOF)[0]\n            ?? $argument->getAttributesOfType(MapUploadedFile::class, ArgumentMetadata::IS_INSTANCEOF)[0]\n            ?? null;\n\n        if (!$attribute) {\n            return [];\n        }\n\n        if ($attribute instanceof MapQueryString && $argument->isVariadic()) {\n            throw new \\LogicException(\\sprintf('Mapping variadic argument \"$%s\" is not supported.', $argument->getName()));\n        }\n\n        if ($attribute instanceof MapRequestPayload) {\n            if ('array' === $argument->getType()) {\n                if (!$attribute->type) {\n                    throw new NearMissValueResolverException(\\sprintf('Please set the $type argument of the #[%s] attribute to the type of the objects in the expected array.', MapRequestPayload::class));\n                }\n            } elseif ($attribute->type && !$argument->isVariadic()) {\n                throw new NearMissValueResolverException(\\sprintf('Please set its type to \"array\" when using argument $type of #[%s].', MapRequestPayload::class));\n            }\n        }\n\n        $attribute->metadata = $argument;\n\n        return [$attribute];\n    }\n\n    public function onKernelControllerArguments(ControllerArgumentsEvent $event): void\n    {\n        $arguments = $event->getArguments();\n\n        foreach ($arguments as $i => $argument) {\n            if ($argument instanceof MapQueryString) {\n                $payloadMapper = $this->mapQueryString(...);\n                $validationFailedCode = $argument->validationFailedStatusCode;\n            } elseif ($argument instanceof MapRequestPayload) {\n                $payloadMapper = $this->mapRequestPayload(...);\n                $validationFailedCode = $argument->validationFailedStatusCode;\n            } elseif ($argument instanceof MapUploadedFile) {\n                $payloadMapper = $this->mapUploadedFile(...);\n                $validationFailedCode = $argument->validationFailedStatusCode;\n            } else {\n                continue;\n            }\n            $request = $event->getRequest();\n\n            if (!$argument->metadata->getType()) {\n                throw new \\LogicException(\\sprintf('Could not resolve the \"$%s\" controller argument: argument should be typed.', $argument->metadata->getName()));\n            }\n\n            if ($this->validator) {\n                $violations = new ConstraintViolationList();\n                try {\n                    $payload = $payloadMapper($request, $argument->metadata, $argument);\n                } catch (PartialDenormalizationException $e) {\n                    $trans = $this->translator ? $this->translator->trans(...) : static fn ($m, $p) => strtr($m, $p);\n                    foreach ($e->getErrors() as $error) {\n                        $parameters = [];\n                        $template = 'This value was of an unexpected type.';\n                        if ($expectedTypes = $error->getExpectedTypes()) {\n                            $template = 'This value should be of type {{ type }}.';\n                            $parameters['{{ type }}'] = implode('|', $expectedTypes);\n                        }\n                        if ($error->canUseMessageForUser()) {\n                            $parameters['hint'] = $error->getMessage();\n                        }\n                        $message = $trans($template, $parameters, $this->translationDomain);\n                        $violations->add(new ConstraintViolation($message, $template, $parameters, null, $error->getPath(), null));\n                    }\n                    $payload = $e->getData();\n                } catch (SerializerInvalidArgumentException $e) {\n                    $violations->add(new ConstraintViolation($e->getMessage(), $e->getMessage(), [], null, '', null));\n                    $payload = null;\n                }\n\n                if (null !== $payload && !\\count($violations)) {\n                    $constraints = $argument->constraints ?? null;\n                    if (\\is_array($payload) && !empty($constraints) && !$constraints instanceof Assert\\All) {\n                        $constraints = new Assert\\All($constraints);\n                    }\n                    $groups = $this->resolveValidationGroups($argument->validationGroups ?? null, $event);\n\n                    if ($argument instanceof MapUploadedFile) {\n                        $violations->addAll($this->validator->startContext()->atPath($argument->metadata->getName())->validate($payload, $constraints, $groups)->getViolations());\n                    } else {\n                        $violations->addAll($this->validator->validate($payload, $constraints, $groups));\n                    }\n                }\n\n                if (\\count($violations)) {\n                    throw HttpException::fromStatusCode($validationFailedCode, implode(\"\\n\", array_map(static fn ($e) => $e->getMessage(), iterator_to_array($violations))), new ValidationFailedException($payload, $violations));\n                }\n            } else {\n                try {\n                    $payload = $payloadMapper($request, $argument->metadata, $argument);\n                } catch (PartialDenormalizationException $e) {\n                    throw HttpException::fromStatusCode($validationFailedCode, implode(\"\\n\", array_map(static fn ($e) => $e->getMessage(), $e->getErrors())), $e);\n                } catch (SerializerInvalidArgumentException $e) {\n                    throw HttpException::fromStatusCode($validationFailedCode, $e->getMessage(), $e);\n                }\n            }\n\n            if ($argument->metadata->isVariadic()) {\n                array_splice($arguments, $i, 1, $payload ?? []);\n                continue;\n            }\n\n            if (null === $payload) {\n                $payload = match (true) {\n                    $argument->metadata->hasDefaultValue() => $argument->metadata->getDefaultValue(),\n                    $argument->metadata->isNullable() => null,\n                    default => throw HttpException::fromStatusCode($validationFailedCode),\n                };\n            }\n\n            $arguments[$i] = $payload;\n        }\n\n        $event->setArguments($arguments);\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        return [\n            KernelEvents::CONTROLLER_ARGUMENTS => 'onKernelControllerArguments',\n        ];\n    }\n\n    private function mapQueryString(Request $request, ArgumentMetadata $argument, MapQueryString $attribute): ?object\n    {\n        if (!($data = $request->query->all($attribute->key)) && ($argument->isNullable() || $argument->hasDefaultValue()) && !$attribute->mapWhenEmpty) {\n            return null;\n        }\n\n        return $this->serializer->denormalize($data, $argument->getType(), 'csv', $attribute->serializationContext + self::CONTEXT_DENORMALIZE + ['filter_bool' => true]);\n    }\n\n    private function mapRequestPayload(Request $request, ArgumentMetadata $argument, MapRequestPayload $attribute): object|array|null\n    {\n        if ('' === $data = $request->request->all() ?: $request->getContent()) {\n            if ($attribute->mapWhenEmpty) {\n                $data = [];\n            } elseif ($argument->isNullable() || $argument->hasDefaultValue()) {\n                return null;\n            }\n        }\n\n        if (null === $format = $request->getContentTypeFormat()) {\n            throw new UnsupportedMediaTypeHttpException('Unsupported format.');\n        }\n\n        if ($attribute->acceptFormat && !\\in_array($format, (array) $attribute->acceptFormat, true)) {\n            throw new UnsupportedMediaTypeHttpException(\\sprintf('Unsupported format, expects \"%s\", but \"%s\" given.', implode('\", \"', (array) $attribute->acceptFormat), $format));\n        }\n\n        $type = match (true) {\n            $argument->isVariadic() => ($attribute->type ?? $argument->getType()).'[]',\n            'array' === $argument->getType() && null !== $attribute->type => $attribute->type.'[]',\n            default => $argument->getType(),\n        };\n\n        if (\\is_array($data)) {\n            $data = $this->mergeParamsAndFiles($data, $request->files->all());\n\n            return $this->serializer->denormalize($data, $type, self::hasNonStringScalar($data) ? $format : 'csv', $attribute->serializationContext + self::CONTEXT_DENORMALIZE + ('form' === $format ? ['filter_bool' => true] : []));\n        }\n\n        if ('form' === $format) {\n            throw new BadRequestHttpException('Request payload contains invalid \"form\" data.');\n        }\n\n        try {\n            return $this->serializer->deserialize($data, $type, $format, self::CONTEXT_DESERIALIZE + $attribute->serializationContext);\n        } catch (UnsupportedFormatException $e) {\n            throw new UnsupportedMediaTypeHttpException(\\sprintf('Unsupported format: \"%s\".', $format), $e);\n        } catch (NotEncodableValueException $e) {\n            throw new BadRequestHttpException(\\sprintf('Request payload contains invalid \"%s\" data.', $format), $e);\n        } catch (UnexpectedPropertyException $e) {\n            throw new BadRequestHttpException(\\sprintf('Request payload contains invalid \"%s\" property.', $e->property), $e);\n        }\n    }\n\n    private function mapUploadedFile(Request $request, ArgumentMetadata $argument, MapUploadedFile $attribute): UploadedFile|array|null\n    {\n        if ($files = $request->files->get($attribute->name ?? $argument->getName())) {\n            return !\\is_array($files) && $argument->isVariadic() ? [$files] : $files;\n        }\n\n        if ($argument->isNullable() || $argument->hasDefaultValue()) {\n            return null;\n        }\n\n        return 'array' === $argument->getType() ? [] : null;\n    }\n\n    private function mergeParamsAndFiles(array $params, array $files): array\n    {\n        $isFilesList = array_is_list($files);\n\n        foreach ($params as $key => $value) {\n            if (\\is_array($value) && \\is_array($files[$key] ?? null)) {\n                $params[$key] = $this->mergeParamsAndFiles($value, $files[$key]);\n                unset($files[$key]);\n            }\n        }\n\n        if (!$isFilesList) {\n            return array_replace($params, $files);\n        }\n\n        foreach ($files as $value) {\n            $params[] = $value;\n        }\n\n        return $params;\n    }\n\n    private function resolveValidationGroups(Expression|string|GroupSequence|\\Closure|array|null $validationGroups, ControllerArgumentsEvent $event): string|GroupSequence|array|null\n    {\n        if ($validationGroups instanceof Expression || $validationGroups instanceof \\Closure) {\n            $validationGroups = $event->evaluate($validationGroups, $this->expressionLanguage);\n        }\n\n        if (null === $validationGroups || \\is_string($validationGroups) || $validationGroups instanceof GroupSequence) {\n            return $validationGroups;\n        }\n\n        if (!\\is_array($validationGroups)) {\n            throw new \\LogicException('The validation groups expression or closure must return a string, an array of strings, or a GroupSequence.');\n        }\n\n        foreach ($validationGroups as $group) {\n            if ($group instanceof Expression) {\n                throw new \\LogicException('Nested expressions in validation groups are not supported. Use a single Expression or a list of strings (or a GroupSequence) instead.');\n            }\n\n            if ($group instanceof \\Closure) {\n                throw new \\LogicException('Nested closures in validation groups are not supported. Use a single Closure or a list of strings (or a GroupSequence) instead.');\n            }\n\n            if ($group instanceof GroupSequence) {\n                throw new \\LogicException('GroupSequence cannot be used inside an array of validation groups. Pass the GroupSequence as the top-level validationGroups value instead.');\n            }\n\n            if (!\\is_string($group)) {\n                throw new \\LogicException('Validation groups must be strings.');\n            }\n        }\n\n        return $validationGroups;\n    }\n\n    private static function hasNonStringScalar(array $data): bool\n    {\n        $stack = [$data];\n\n        while ($stack) {\n            foreach (array_pop($stack) as $v) {\n                if (\\is_array($v)) {\n                    $stack[] = $v;\n                } elseif (!\\is_string($v)) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "Controller/ArgumentResolver/RequestValueResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Exception\\NearMissValueResolverException;\n\n/**\n * Yields the same instance as the request object passed along.\n *\n * @author Iltar van der Berg <kjarli@gmail.com>\n */\nfinal class RequestValueResolver implements ValueResolverInterface\n{\n    public function resolve(Request $request, ArgumentMetadata $argument): array\n    {\n        if (Request::class === $argument->getType() || is_subclass_of($argument->getType(), Request::class)) {\n            return [$request];\n        }\n\n        if (str_ends_with($argument->getType() ?? '', '\\\\Request')) {\n            throw new NearMissValueResolverException(\\sprintf('Looks like you required a Request object with the wrong class name \"%s\". Did you mean to use \"%s\" instead?', $argument->getType(), Request::class));\n        }\n\n        return [];\n    }\n}\n"
  },
  {
    "path": "Controller/ArgumentResolver/ServiceValueResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\n\nuse Psr\\Container\\ContainerInterface;\nuse Symfony\\Component\\DependencyInjection\\Exception\\RuntimeException;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Exception\\NearMissValueResolverException;\n\n/**\n * Yields a service keyed by _controller and argument name.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class ServiceValueResolver implements ValueResolverInterface\n{\n    public function __construct(\n        private ContainerInterface $container,\n    ) {\n    }\n\n    public function resolve(Request $request, ArgumentMetadata $argument): array\n    {\n        $controller = $request->attributes->get('_controller');\n\n        if (\\is_array($controller) && \\is_callable($controller, true) && \\is_string($controller[0])) {\n            $controller = $controller[0].'::'.$controller[1];\n        } elseif (!\\is_string($controller) || '' === $controller) {\n            return [];\n        }\n\n        if ('\\\\' === $controller[0]) {\n            $controller = ltrim($controller, '\\\\');\n        }\n\n        if (!$this->container->has($controller) && false !== $i = strrpos($controller, ':')) {\n            $controller = substr($controller, 0, $i).strtolower(substr($controller, $i));\n        }\n\n        if (!$this->container->has($controller) || !$this->container->get($controller)->has($argument->getName())) {\n            return [];\n        }\n\n        try {\n            return [$this->container->get($controller)->get($argument->getName())];\n        } catch (RuntimeException $e) {\n            $what = 'argument $'.$argument->getName();\n            $message = str_replace(\\sprintf('service \"%s\"', $argument->getName()), $what, $e->getMessage());\n            $what .= \\sprintf(' of \"%s()\"', $controller);\n            $message = preg_replace('/service \"\\.service_locator\\.[^\"]++\"/', $what, $message);\n\n            if ($e->getMessage() === $message) {\n                $message = \\sprintf('Cannot resolve %s: %s', $what, $message);\n            }\n\n            throw new NearMissValueResolverException($message, $e->getCode(), $e);\n        }\n    }\n}\n"
  },
  {
    "path": "Controller/ArgumentResolver/SessionValueResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Session\\SessionInterface;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\n\n/**\n * Yields the Session.\n *\n * @author Iltar van der Berg <kjarli@gmail.com>\n */\nfinal class SessionValueResolver implements ValueResolverInterface\n{\n    public function resolve(Request $request, ArgumentMetadata $argument): array\n    {\n        if (!$request->hasSession()) {\n            return [];\n        }\n\n        $type = $argument->getType();\n        if (SessionInterface::class !== $type && !is_subclass_of($type, SessionInterface::class)) {\n            return [];\n        }\n\n        return $request->getSession() instanceof $type ? [$request->getSession()] : [];\n    }\n}\n"
  },
  {
    "path": "Controller/ArgumentResolver/TraceableValueResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\Stopwatch\\Stopwatch;\n\n/**\n * Provides timing information via the stopwatch.\n *\n * @author Iltar van der Berg <kjarli@gmail.com>\n */\nfinal class TraceableValueResolver implements ValueResolverInterface\n{\n    public function __construct(\n        private ValueResolverInterface $inner,\n        private Stopwatch $stopwatch,\n    ) {\n    }\n\n    public function resolve(Request $request, ArgumentMetadata $argument): iterable\n    {\n        $method = $this->inner::class.'::'.__FUNCTION__;\n        $this->stopwatch->start($method, 'controller.argument_value_resolver');\n\n        yield from $this->inner->resolve($request, $argument);\n\n        $this->stopwatch->stop($method);\n    }\n}\n"
  },
  {
    "path": "Controller/ArgumentResolver/UidValueResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;\nuse Symfony\\Component\\Uid\\AbstractUid;\n\nfinal class UidValueResolver implements ValueResolverInterface\n{\n    public function resolve(Request $request, ArgumentMetadata $argument): array\n    {\n        if ($argument->isVariadic()\n            || !\\is_string($value = $request->attributes->get($argument->getName()))\n            || null === ($uidClass = $argument->getType())\n            || !is_subclass_of($uidClass, AbstractUid::class, true)\n        ) {\n            return [];\n        }\n\n        try {\n            return [$uidClass::fromString($value)];\n        } catch (\\InvalidArgumentException $e) {\n            throw new NotFoundHttpException(\\sprintf('The uid for the \"%s\" parameter is invalid.', $argument->getName()), $e);\n        }\n    }\n}\n"
  },
  {
    "path": "Controller/ArgumentResolver/VariadicValueResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\n\n/**\n * Yields a variadic argument's values from the request attributes.\n *\n * @author Iltar van der Berg <kjarli@gmail.com>\n */\nfinal class VariadicValueResolver implements ValueResolverInterface\n{\n    public function resolve(Request $request, ArgumentMetadata $argument): array\n    {\n        if (!$argument->isVariadic() || !$request->attributes->has($argument->getName())) {\n            return [];\n        }\n\n        $values = $request->attributes->get($argument->getName());\n\n        if (!\\is_array($values)) {\n            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)));\n        }\n\n        return $values;\n    }\n}\n"
  },
  {
    "path": "Controller/ArgumentResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller;\n\nuse Psr\\Container\\ContainerInterface;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Attribute\\ValueResolver;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\DefaultValueResolver;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\RequestAttributeValueResolver;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\RequestValueResolver;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\SessionValueResolver;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\VariadicValueResolver;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadataFactory;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadataFactoryInterface;\nuse Symfony\\Component\\HttpKernel\\Exception\\NearMissValueResolverException;\nuse Symfony\\Component\\HttpKernel\\Exception\\ResolverNotFoundException;\nuse Symfony\\Contracts\\Service\\ServiceProviderInterface;\n\n/**\n * Responsible for resolving the arguments passed to an action.\n *\n * @author Iltar van der Berg <kjarli@gmail.com>\n */\nfinal class ArgumentResolver implements ArgumentResolverInterface\n{\n    private ArgumentMetadataFactoryInterface $argumentMetadataFactory;\n    private iterable $argumentValueResolvers;\n\n    /**\n     * @param iterable<mixed, ValueResolverInterface> $argumentValueResolvers\n     */\n    public function __construct(\n        ?ArgumentMetadataFactoryInterface $argumentMetadataFactory = null,\n        iterable $argumentValueResolvers = [],\n        private ?ContainerInterface $namedResolvers = null,\n    ) {\n        $this->argumentMetadataFactory = $argumentMetadataFactory ?? new ArgumentMetadataFactory();\n        $this->argumentValueResolvers = $argumentValueResolvers ?: self::getDefaultArgumentValueResolvers();\n    }\n\n    public function getArguments(Request $request, callable $controller, ?\\ReflectionFunctionAbstract $reflector = null): array\n    {\n        $arguments = [];\n\n        foreach ($this->argumentMetadataFactory->createArgumentMetadata($controller, $reflector) as $metadata) {\n            $argumentValueResolvers = $this->argumentValueResolvers;\n            $disabledResolvers = [];\n\n            if ($this->namedResolvers && $attributes = $metadata->getAttributesOfType(ValueResolver::class, $metadata::IS_INSTANCEOF)) {\n                $resolverName = null;\n                foreach ($attributes as $attribute) {\n                    if ($attribute->disabled) {\n                        $disabledResolvers[$attribute->resolver] = true;\n                    } elseif ($resolverName) {\n                        throw new \\LogicException(\\sprintf('You can only pin one resolver per argument, but argument \"$%s\" of \"%s()\" has more.', $metadata->getName(), $metadata->getControllerName()));\n                    } else {\n                        $resolverName = $attribute->resolver;\n                    }\n                }\n\n                if ($resolverName) {\n                    if (!$this->namedResolvers->has($resolverName)) {\n                        throw new ResolverNotFoundException($resolverName, $this->namedResolvers instanceof ServiceProviderInterface ? array_keys($this->namedResolvers->getProvidedServices()) : []);\n                    }\n\n                    $argumentValueResolvers = [\n                        $this->namedResolvers->get($resolverName),\n                        new RequestAttributeValueResolver(),\n                        new DefaultValueResolver(),\n                    ];\n                }\n            }\n\n            $valueResolverExceptions = [];\n            foreach ($argumentValueResolvers as $name => $resolver) {\n                if (isset($disabledResolvers[\\is_int($name) ? $resolver::class : $name])) {\n                    continue;\n                }\n\n                try {\n                    $count = 0;\n                    foreach ($resolver->resolve($request, $metadata) as $argument) {\n                        ++$count;\n                        $arguments[] = $argument;\n                    }\n                } catch (NearMissValueResolverException $e) {\n                    $valueResolverExceptions[] = $e;\n                }\n\n                if (1 < $count && !$metadata->isVariadic()) {\n                    throw new \\InvalidArgumentException(\\sprintf('\"%s::resolve()\" must yield at most one value for non-variadic arguments.', get_debug_type($resolver)));\n                }\n\n                if ($count) {\n                    // continue to the next controller argument\n                    continue 2;\n                }\n            }\n\n            $reasons = array_map(static fn (NearMissValueResolverException $e) => $e->getMessage(), $valueResolverExceptions);\n            if (!$reasons) {\n                $reasons[] = '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.';\n            }\n\n            $reasonCounter = 1;\n            if (\\count($reasons) > 1) {\n                foreach ($reasons as $i => $reason) {\n                    $reasons[$i] = $reasonCounter.') '.$reason;\n                    ++$reasonCounter;\n                }\n            }\n\n            throw new \\RuntimeException(\\sprintf('Controller \"%s\" requires the \"$%s\" argument that could not be resolved. '.($reasonCounter > 1 ? 'Possible reasons: ' : '').'%s', $metadata->getControllerName(), $metadata->getName(), implode(' ', $reasons)));\n        }\n\n        return $arguments;\n    }\n\n    /**\n     * @return iterable<int, ValueResolverInterface>\n     */\n    public static function getDefaultArgumentValueResolvers(): iterable\n    {\n        return [\n            new RequestAttributeValueResolver(),\n            new RequestValueResolver(),\n            new SessionValueResolver(),\n            new DefaultValueResolver(),\n            new VariadicValueResolver(),\n        ];\n    }\n}\n"
  },
  {
    "path": "Controller/ArgumentResolverInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\n\n/**\n * An ArgumentResolverInterface instance knows how to determine the\n * arguments for a specific action.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface ArgumentResolverInterface\n{\n    /**\n     * Returns the arguments to pass to the controller.\n     *\n     * @throws \\RuntimeException When no value could be provided for a required argument\n     */\n    public function getArguments(Request $request, callable $controller, ?\\ReflectionFunctionAbstract $reflector = null): array;\n}\n"
  },
  {
    "path": "Controller/ContainerControllerResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller;\n\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\DependencyInjection\\Container;\n\n/**\n * A controller resolver searching for a controller in a psr-11 container when using the \"service::method\" notation.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>\n */\nclass ContainerControllerResolver extends ControllerResolver\n{\n    public function __construct(\n        protected ContainerInterface $container,\n        ?LoggerInterface $logger = null,\n    ) {\n        parent::__construct($logger);\n    }\n\n    protected function instantiateController(string $class): object\n    {\n        $class = ltrim($class, '\\\\');\n\n        if ($this->container->has($class)) {\n            return $this->container->get($class);\n        }\n\n        try {\n            return parent::instantiateController($class);\n        } catch (\\Error $e) {\n        }\n\n        $this->throwExceptionIfControllerWasRemoved($class, $e);\n\n        if ($e instanceof \\ArgumentCountError) {\n            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);\n        }\n\n        throw new \\InvalidArgumentException(\\sprintf('Controller \"%s\" does neither exist as service nor as class.', $class), 0, $e);\n    }\n\n    private function throwExceptionIfControllerWasRemoved(string $controller, \\Throwable $previous): void\n    {\n        if ($this->container instanceof Container && isset($this->container->getRemovedIds()[$controller])) {\n            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);\n        }\n    }\n}\n"
  },
  {
    "path": "Controller/ControllerReference.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller;\n\nuse Symfony\\Component\\HttpKernel\\Fragment\\FragmentRendererInterface;\n\n/**\n * Acts as a marker and a data holder for a Controller.\n *\n * Some methods in Symfony accept both a URI (as a string) or a controller as\n * an argument. In the latter case, instead of passing an array representing\n * the controller, you can use an instance of this class.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @see FragmentRendererInterface\n */\nclass ControllerReference\n{\n    public array $attributes = [];\n    public array $query = [];\n\n    /**\n     * @param string $controller The controller name\n     * @param array  $attributes An array of parameters to add to the Request attributes\n     * @param array  $query      An array of parameters to add to the Request query string\n     */\n    public function __construct(\n        public string $controller,\n        array $attributes = [],\n        array $query = [],\n    ) {\n        $this->attributes = $attributes;\n        $this->query = $query;\n    }\n}\n"
  },
  {
    "path": "Controller/ControllerResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller;\n\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\HttpFoundation\\Exception\\BadRequestException;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Attribute\\AsController;\n\n/**\n * This implementation uses the '_controller' request attribute to determine\n * the controller to execute.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n * @author Tobias Schultze <http://tobion.de>\n */\nclass ControllerResolver implements ControllerResolverInterface\n{\n    private array $allowedControllerTypes = [];\n    private array $allowedControllerAttributes = [AsController::class => AsController::class];\n\n    public function __construct(\n        private ?LoggerInterface $logger = null,\n    ) {\n    }\n\n    /**\n     * @param array<class-string> $types\n     * @param array<class-string> $attributes\n     */\n    public function allowControllers(array $types = [], array $attributes = []): void\n    {\n        foreach ($types as $type) {\n            $this->allowedControllerTypes[$type] = $type;\n        }\n\n        foreach ($attributes as $attribute) {\n            $this->allowedControllerAttributes[$attribute] = $attribute;\n        }\n    }\n\n    /**\n     * @throws BadRequestException when the request has attribute \"_check_controller_is_allowed\" set to true and the controller is not allowed\n     */\n    public function getController(Request $request): callable|false\n    {\n        if (!$controller = $request->attributes->get('_controller')) {\n            $this->logger?->warning('Unable to look for the controller as the \"_controller\" parameter is missing.');\n\n            return false;\n        }\n\n        if (\\is_array($controller)) {\n            if (isset($controller[0]) && \\is_string($controller[0]) && isset($controller[1])) {\n                try {\n                    $controller[0] = $this->instantiateController($controller[0]);\n                } catch (\\Error|\\LogicException $e) {\n                    if (\\is_callable($controller)) {\n                        return $this->checkController($request, $controller);\n                    }\n\n                    throw $e;\n                }\n            }\n\n            if (!\\is_callable($controller)) {\n                throw new \\InvalidArgumentException(\\sprintf('The controller for URI \"%s\" is not callable: ', $request->getPathInfo()).$this->getControllerError($controller));\n            }\n\n            return $this->checkController($request, $controller);\n        }\n\n        if (\\is_object($controller)) {\n            if (!\\is_callable($controller)) {\n                throw new \\InvalidArgumentException(\\sprintf('The controller for URI \"%s\" is not callable: ', $request->getPathInfo()).$this->getControllerError($controller));\n            }\n\n            return $this->checkController($request, $controller);\n        }\n\n        if (\\function_exists($controller)) {\n            return $this->checkController($request, $controller);\n        }\n\n        try {\n            $callable = $this->createController($controller);\n        } catch (\\InvalidArgumentException $e) {\n            throw new \\InvalidArgumentException(\\sprintf('The controller for URI \"%s\" is not callable: ', $request->getPathInfo()).$e->getMessage(), 0, $e);\n        }\n\n        if (!\\is_callable($callable)) {\n            throw new \\InvalidArgumentException(\\sprintf('The controller for URI \"%s\" is not callable: ', $request->getPathInfo()).$this->getControllerError($callable));\n        }\n\n        return $this->checkController($request, $callable);\n    }\n\n    /**\n     * Returns a callable for the given controller.\n     *\n     * @throws \\InvalidArgumentException When the controller cannot be created\n     */\n    protected function createController(string $controller): callable\n    {\n        if (!str_contains($controller, '::')) {\n            $controller = $this->instantiateController($controller);\n\n            if (!\\is_callable($controller)) {\n                throw new \\InvalidArgumentException($this->getControllerError($controller));\n            }\n\n            return $controller;\n        }\n\n        [$class, $method] = explode('::', $controller, 2);\n\n        try {\n            $controller = [$this->instantiateController($class), $method];\n        } catch (\\Error|\\LogicException $e) {\n            try {\n                if ((new \\ReflectionMethod($class, $method))->isStatic()) {\n                    return $class.'::'.$method;\n                }\n            } catch (\\ReflectionException) {\n                throw $e;\n            }\n\n            throw $e;\n        }\n\n        if (!\\is_callable($controller)) {\n            throw new \\InvalidArgumentException($this->getControllerError($controller));\n        }\n\n        return $controller;\n    }\n\n    /**\n     * Returns an instantiated controller.\n     */\n    protected function instantiateController(string $class): object\n    {\n        return new $class();\n    }\n\n    private function getControllerError(mixed $callable): string\n    {\n        if (\\is_string($callable)) {\n            if (str_contains($callable, '::')) {\n                $callable = explode('::', $callable, 2);\n            } else {\n                return \\sprintf('Function \"%s\" does not exist.', $callable);\n            }\n        }\n\n        if (\\is_object($callable)) {\n            $availableMethods = $this->getClassMethodsWithoutMagicMethods($callable);\n            $alternativeMsg = $availableMethods ? \\sprintf(' or use one of the available methods: \"%s\"', implode('\", \"', $availableMethods)) : '';\n\n            return \\sprintf('Controller class \"%s\" cannot be called without a method name. You need to implement \"__invoke\"%s.', get_debug_type($callable), $alternativeMsg);\n        }\n\n        if (!\\is_array($callable)) {\n            return \\sprintf('Invalid type for controller given, expected string, array or object, got \"%s\".', get_debug_type($callable));\n        }\n\n        if (!isset($callable[0]) || !isset($callable[1]) || 2 !== \\count($callable)) {\n            return 'Invalid array callable, expected [controller, method].';\n        }\n\n        [$controller, $method] = $callable;\n\n        if (\\is_string($controller) && !class_exists($controller)) {\n            return \\sprintf('Class \"%s\" does not exist.', $controller);\n        }\n\n        $className = \\is_object($controller) ? get_debug_type($controller) : $controller;\n\n        if (method_exists($controller, $method)) {\n            return \\sprintf('Method \"%s\" on class \"%s\" should be public and non-abstract.', $method, $className);\n        }\n\n        $collection = $this->getClassMethodsWithoutMagicMethods($controller);\n\n        $alternatives = [];\n\n        foreach ($collection as $item) {\n            $lev = levenshtein($method, $item);\n\n            if ($lev <= \\strlen($method) / 3 || str_contains($item, $method)) {\n                $alternatives[] = $item;\n            }\n        }\n\n        asort($alternatives);\n\n        $message = \\sprintf('Expected method \"%s\" on class \"%s\"', $method, $className);\n\n        if (\\count($alternatives) > 0) {\n            $message .= \\sprintf(', did you mean \"%s\"?', implode('\", \"', $alternatives));\n        } else {\n            $message .= \\sprintf('. Available methods: \"%s\".', implode('\", \"', $collection));\n        }\n\n        return $message;\n    }\n\n    private function getClassMethodsWithoutMagicMethods($classOrObject): array\n    {\n        $methods = get_class_methods($classOrObject);\n\n        return array_filter($methods, static fn (string $method) => 0 !== strncmp($method, '__', 2));\n    }\n\n    private function checkController(Request $request, callable $controller): callable\n    {\n        if (!$request->attributes->get('_check_controller_is_allowed', false)) {\n            return $controller;\n        }\n\n        $r = null;\n\n        if (\\is_array($controller)) {\n            [$class, $name] = $controller;\n            $name = (\\is_string($class) ? $class : $class::class).'::'.$name;\n        } elseif (\\is_object($controller) && !$controller instanceof \\Closure) {\n            $class = $controller;\n            $name = $class::class.'::__invoke';\n        } else {\n            $r = new \\ReflectionFunction($controller);\n            $name = $r->name;\n\n            if ($r->isAnonymous()) {\n                $name = $class = \\Closure::class;\n            } elseif ($class = $r->getClosureCalledClass()) {\n                $class = $class->name;\n                $name = $class.'::'.$name;\n            }\n        }\n\n        if ($class) {\n            foreach ($this->allowedControllerTypes as $type) {\n                if (is_a($class, $type, true)) {\n                    return $controller;\n                }\n            }\n        }\n\n        $r ??= new \\ReflectionClass($class);\n\n        foreach ($r->getAttributes() as $attribute) {\n            if (isset($this->allowedControllerAttributes[$attribute->getName()])) {\n                return $controller;\n            }\n        }\n\n        if (str_contains($name, '@anonymous')) {\n            $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]++/', static fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $name);\n        }\n\n        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));\n    }\n}\n"
  },
  {
    "path": "Controller/ControllerResolverInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\n\n/**\n * A ControllerResolverInterface implementation knows how to determine the\n * controller to execute based on a Request object.\n *\n * A Controller can be any valid PHP callable.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface ControllerResolverInterface\n{\n    /**\n     * Returns the Controller instance associated with a Request.\n     *\n     * As several resolvers can exist for a single application, a resolver must\n     * return false when it is not able to determine the controller.\n     *\n     * The resolver must only throw an exception when it should be able to load a\n     * controller but cannot because of some errors made by the developer.\n     *\n     * @return callable|false A PHP callable representing the Controller,\n     *                        or false if this resolver is not able to determine the controller\n     *\n     * @throws \\LogicException If a controller was found based on the request but it is not callable\n     */\n    public function getController(Request $request): callable|false;\n}\n"
  },
  {
    "path": "Controller/ErrorController.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller;\n\nuse Symfony\\Component\\ErrorHandler\\ErrorRenderer\\ErrorRendererInterface;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\n\n/**\n * Renders error or exception pages from a given FlattenException.\n *\n * @author Yonel Ceruto <yonelceruto@gmail.com>\n * @author Matthias Pigulla <mp@webfactory.de>\n */\nclass ErrorController\n{\n    public function __construct(\n        private HttpKernelInterface $kernel,\n        private string|object|array|null $controller,\n        private ErrorRendererInterface $errorRenderer,\n    ) {\n    }\n\n    public function __invoke(\\Throwable $exception): Response\n    {\n        $exception = $this->errorRenderer->render($exception);\n\n        return new Response($exception->getAsString(), $exception->getStatusCode(), $exception->getHeaders());\n    }\n\n    public function preview(Request $request, int $code): Response\n    {\n        /*\n         * This Request mimics the parameters set by\n         * \\Symfony\\Component\\HttpKernel\\EventListener\\ErrorListener::duplicateRequest, with\n         * the additional \"showException\" flag.\n         */\n        $subRequest = $request->duplicate(null, null, [\n            '_controller' => $this->controller,\n            'exception' => new HttpException($code, 'This is a sample exception.'),\n            'logger' => null,\n            'showException' => false,\n        ]);\n\n        return $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);\n    }\n}\n"
  },
  {
    "path": "Controller/TraceableArgumentResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\Stopwatch\\Stopwatch;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass TraceableArgumentResolver implements ArgumentResolverInterface\n{\n    public function __construct(\n        private ArgumentResolverInterface $resolver,\n        private Stopwatch $stopwatch,\n    ) {\n    }\n\n    public function getArguments(Request $request, callable $controller, ?\\ReflectionFunctionAbstract $reflector = null): array\n    {\n        $e = $this->stopwatch->start('controller.get_arguments');\n\n        try {\n            return $this->resolver->getArguments($request, $controller, $reflector);\n        } finally {\n            $e->stop();\n        }\n    }\n}\n"
  },
  {
    "path": "Controller/TraceableControllerResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\Stopwatch\\Stopwatch;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass TraceableControllerResolver implements ControllerResolverInterface\n{\n    public function __construct(\n        private ControllerResolverInterface $resolver,\n        private Stopwatch $stopwatch,\n    ) {\n    }\n\n    public function getController(Request $request): callable|false\n    {\n        $e = $this->stopwatch->start('controller.get_callable');\n\n        try {\n            return $this->resolver->getController($request);\n        } finally {\n            $e->stop();\n        }\n    }\n}\n"
  },
  {
    "path": "Controller/ValueResolverInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Controller;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\n\n/**\n * Responsible for resolving the value of an argument based on its metadata.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\ninterface ValueResolverInterface\n{\n    /**\n     * Returns the possible value(s).\n     */\n    public function resolve(Request $request, ArgumentMetadata $argument): iterable;\n}\n"
  },
  {
    "path": "ControllerMetadata/ArgumentMetadata.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\ControllerMetadata;\n\n/**\n * Responsible for storing metadata of an argument.\n *\n * @author Iltar van der Berg <kjarli@gmail.com>\n */\nclass ArgumentMetadata\n{\n    public const IS_INSTANCEOF = 2;\n\n    /**\n     * @param object[] $attributes\n     */\n    public function __construct(\n        private string $name,\n        private ?string $type,\n        private bool $isVariadic,\n        private bool $hasDefaultValue,\n        private mixed $defaultValue,\n        private bool $isNullable = false,\n        private array $attributes = [],\n        private string $controllerName = 'n/a',\n    ) {\n        $this->isNullable = $isNullable || null === $type || ($hasDefaultValue && null === $defaultValue);\n    }\n\n    /**\n     * Returns the name as given in PHP, $foo would yield \"foo\".\n     */\n    public function getName(): string\n    {\n        return $this->name;\n    }\n\n    /**\n     * Returns the type of the argument.\n     */\n    public function getType(): ?string\n    {\n        return $this->type;\n    }\n\n    /**\n     * Returns whether the argument is defined as \"...$variadic\".\n     */\n    public function isVariadic(): bool\n    {\n        return $this->isVariadic;\n    }\n\n    /**\n     * Returns whether the argument has a default value.\n     *\n     * Implies whether an argument is optional.\n     */\n    public function hasDefaultValue(): bool\n    {\n        return $this->hasDefaultValue;\n    }\n\n    /**\n     * Returns whether the argument accepts null values.\n     */\n    public function isNullable(): bool\n    {\n        return $this->isNullable;\n    }\n\n    /**\n     * Returns the default value of the argument.\n     *\n     * @throws \\LogicException if no default value is present; {@see self::hasDefaultValue()}\n     */\n    public function getDefaultValue(): mixed\n    {\n        if (!$this->hasDefaultValue) {\n            throw new \\LogicException(\\sprintf('Argument $%s does not have a default value. Use \"%s::hasDefaultValue()\" to avoid this exception.', $this->name, __CLASS__));\n        }\n\n        return $this->defaultValue;\n    }\n\n    /**\n     * @param class-string          $name\n     * @param self::IS_INSTANCEOF|0 $flags\n     *\n     * @return array<object>\n     */\n    public function getAttributes(?string $name = null, int $flags = 0): array\n    {\n        if (!$name) {\n            return $this->attributes;\n        }\n\n        return $this->getAttributesOfType($name, $flags);\n    }\n\n    /**\n     * @template T of object\n     *\n     * @param class-string<T>       $name\n     * @param self::IS_INSTANCEOF|0 $flags\n     *\n     * @return array<T>\n     */\n    public function getAttributesOfType(string $name, int $flags = 0): array\n    {\n        $attributes = [];\n        if ($flags & self::IS_INSTANCEOF) {\n            foreach ($this->attributes as $attribute) {\n                if ($attribute instanceof $name) {\n                    $attributes[] = $attribute;\n                }\n            }\n        } else {\n            foreach ($this->attributes as $attribute) {\n                if ($attribute::class === $name) {\n                    $attributes[] = $attribute;\n                }\n            }\n        }\n\n        return $attributes;\n    }\n\n    public function getControllerName(): string\n    {\n        return $this->controllerName;\n    }\n}\n"
  },
  {
    "path": "ControllerMetadata/ArgumentMetadataFactory.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\ControllerMetadata;\n\n/**\n * Builds {@see ArgumentMetadata} objects based on the given Controller.\n *\n * @author Iltar van der Berg <kjarli@gmail.com>\n */\nfinal class ArgumentMetadataFactory implements ArgumentMetadataFactoryInterface\n{\n    public function createArgumentMetadata(string|object|array $controller, ?\\ReflectionFunctionAbstract $reflector = null): array\n    {\n        $arguments = [];\n        $reflector ??= new \\ReflectionFunction($controller(...));\n        $controllerName = $this->getPrettyName($reflector);\n\n        foreach ($reflector->getParameters() as $param) {\n            $attributes = [];\n            foreach ($param->getAttributes() as $reflectionAttribute) {\n                if (class_exists($reflectionAttribute->getName())) {\n                    $attributes[] = $reflectionAttribute->newInstance();\n                }\n            }\n\n            $arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param), $param->isVariadic(), $param->isDefaultValueAvailable(), $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, $param->allowsNull(), $attributes, $controllerName);\n        }\n\n        return $arguments;\n    }\n\n    /**\n     * Returns an associated type to the given parameter if available.\n     */\n    private function getType(\\ReflectionParameter $parameter): ?string\n    {\n        if (!$type = $parameter->getType()) {\n            return null;\n        }\n        $name = $type instanceof \\ReflectionNamedType ? $type->getName() : (string) $type;\n\n        return match (strtolower($name)) {\n            'self' => $parameter->getDeclaringClass()?->name,\n            'parent' => get_parent_class($parameter->getDeclaringClass()?->name ?? '') ?: null,\n            default => $name,\n        };\n    }\n\n    private function getPrettyName(\\ReflectionFunctionAbstract $r): string\n    {\n        $name = $r->name;\n\n        if ($r instanceof \\ReflectionMethod) {\n            return $r->class.'::'.$name;\n        }\n\n        if ($r->isAnonymous() || !$class = $r->getClosureCalledClass()) {\n            return $name;\n        }\n\n        return $class->name.'::'.$name;\n    }\n}\n"
  },
  {
    "path": "ControllerMetadata/ArgumentMetadataFactoryInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\ControllerMetadata;\n\n/**\n * Builds method argument data.\n *\n * @author Iltar van der Berg <kjarli@gmail.com>\n */\ninterface ArgumentMetadataFactoryInterface\n{\n    /**\n     * @return ArgumentMetadata[]\n     */\n    public function createArgumentMetadata(string|object|array $controller, ?\\ReflectionFunctionAbstract $reflector = null): array;\n}\n"
  },
  {
    "path": "DataCollector/AjaxDataCollector.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DataCollector;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\n\n/**\n * @author Bart van den Burg <bart@burgov.nl>\n *\n * @final\n */\nclass AjaxDataCollector extends DataCollector\n{\n    public function collect(Request $request, Response $response, ?\\Throwable $exception = null): void\n    {\n        // all collecting is done client side\n    }\n\n    public function reset(): void\n    {\n        // all collecting is done client side\n    }\n\n    public function getName(): string\n    {\n        return 'ajax';\n    }\n}\n"
  },
  {
    "path": "DataCollector/ConfigDataCollector.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DataCollector;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Kernel;\nuse Symfony\\Component\\HttpKernel\\KernelInterface;\nuse Symfony\\Component\\Runtime\\RunnerInterface;\nuse Symfony\\Component\\VarDumper\\Caster\\ClassStub;\nuse Symfony\\Component\\VarDumper\\Cloner\\Data;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @final\n */\nclass ConfigDataCollector extends DataCollector implements LateDataCollectorInterface\n{\n    private KernelInterface $kernel;\n\n    /**\n     * Sets the Kernel associated with this Request.\n     */\n    public function setKernel(KernelInterface $kernel): void\n    {\n        $this->kernel = $kernel;\n    }\n\n    public function collect(Request $request, Response $response, ?\\Throwable $exception = null): void\n    {\n        $eom = \\DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE);\n        $eol = \\DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE);\n\n        $xdebugMode = getenv('XDEBUG_MODE') ?: \\ini_get('xdebug.mode');\n\n        $this->data = [\n            'token' => $response->headers->get('X-Debug-Token'),\n            'symfony_version' => Kernel::VERSION,\n            'symfony_minor_version' => \\sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION),\n            'symfony_lts' => 4 === Kernel::MINOR_VERSION,\n            'symfony_state' => $this->determineSymfonyState(),\n            'symfony_eom' => $eom->format('F Y'),\n            'symfony_eol' => $eol->format('F Y'),\n            'env' => isset($this->kernel) ? $this->kernel->getEnvironment() : 'n/a',\n            'debug' => isset($this->kernel) ? $this->kernel->isDebug() : 'n/a',\n            'php_version' => \\PHP_VERSION,\n            'php_architecture' => \\PHP_INT_SIZE * 8,\n            'php_intl_locale' => class_exists(\\Locale::class, false) && \\Locale::getDefault() ? \\Locale::getDefault() : 'n/a',\n            'php_timezone' => date_default_timezone_get(),\n            'xdebug_enabled' => \\extension_loaded('xdebug'),\n            'xdebug_status' => \\extension_loaded('xdebug') ? ($xdebugMode && 'off' !== $xdebugMode ? 'Enabled ('.$xdebugMode.')' : 'Not enabled') : 'Not installed',\n            'apcu_enabled' => \\extension_loaded('apcu') && filter_var(\\ini_get('apc.enabled'), \\FILTER_VALIDATE_BOOL),\n            'apcu_status' => \\extension_loaded('apcu') ? (filter_var(\\ini_get('apc.enabled'), \\FILTER_VALIDATE_BOOLEAN) ? 'Enabled' : 'Not enabled') : 'Not installed',\n            'zend_opcache_enabled' => \\extension_loaded('Zend OPcache') && filter_var(\\ini_get('opcache.enable'), \\FILTER_VALIDATE_BOOL),\n            'zend_opcache_status' => \\extension_loaded('Zend OPcache') ? (filter_var(\\ini_get('opcache.enable'), \\FILTER_VALIDATE_BOOLEAN) ? 'Enabled' : 'Not enabled') : 'Not installed',\n            'bundles' => [],\n            'sapi_name' => \\PHP_SAPI,\n            'runner_class' => $this->determineRunnerClass(),\n        ];\n\n        if (isset($this->kernel)) {\n            foreach ($this->kernel->getBundles() as $name => $bundle) {\n                $this->data['bundles'][$name] = new ClassStub($bundle::class);\n            }\n        }\n\n        if (preg_match('~^(\\d+(?:\\.\\d+)*)(.+)?$~', $this->data['php_version'], $matches) && isset($matches[2])) {\n            $this->data['php_version'] = $matches[1];\n            $this->data['php_version_extra'] = $matches[2];\n        }\n    }\n\n    public function lateCollect(): void\n    {\n        $this->data = $this->cloneVar($this->data);\n    }\n\n    /**\n     * Gets the token.\n     */\n    public function getToken(): ?string\n    {\n        return $this->data['token'];\n    }\n\n    /**\n     * Gets the Symfony version.\n     */\n    public function getSymfonyVersion(): string\n    {\n        return $this->data['symfony_version'];\n    }\n\n    /**\n     * Returns the state of the current Symfony release\n     * as one of: unknown, dev, stable, eom, eol.\n     */\n    public function getSymfonyState(): string\n    {\n        return $this->data['symfony_state'];\n    }\n\n    /**\n     * Returns the minor Symfony version used (without patch numbers of extra\n     * suffix like \"RC\", \"beta\", etc.).\n     */\n    public function getSymfonyMinorVersion(): string\n    {\n        return $this->data['symfony_minor_version'];\n    }\n\n    public function isSymfonyLts(): bool\n    {\n        return $this->data['symfony_lts'];\n    }\n\n    /**\n     * Returns the human readable date when this Symfony version ends its\n     * maintenance period.\n     */\n    public function getSymfonyEom(): string\n    {\n        return $this->data['symfony_eom'];\n    }\n\n    /**\n     * Returns the human readable date when this Symfony version reaches its\n     * \"end of life\" and won't receive bugs or security fixes.\n     */\n    public function getSymfonyEol(): string\n    {\n        return $this->data['symfony_eol'];\n    }\n\n    /**\n     * Gets the PHP version.\n     */\n    public function getPhpVersion(): string\n    {\n        return $this->data['php_version'];\n    }\n\n    /**\n     * Gets the PHP version extra part.\n     */\n    public function getPhpVersionExtra(): ?string\n    {\n        return $this->data['php_version_extra'] ?? null;\n    }\n\n    public function getPhpArchitecture(): int\n    {\n        return $this->data['php_architecture'];\n    }\n\n    public function getPhpIntlLocale(): string\n    {\n        return $this->data['php_intl_locale'];\n    }\n\n    public function getPhpTimezone(): string\n    {\n        return $this->data['php_timezone'];\n    }\n\n    /**\n     * Gets the environment.\n     */\n    public function getEnv(): string\n    {\n        return $this->data['env'];\n    }\n\n    /**\n     * Returns true if the debug is enabled.\n     *\n     * @return bool|string true if debug is enabled, false otherwise or a string if no kernel was set\n     */\n    public function isDebug(): bool|string\n    {\n        return $this->data['debug'];\n    }\n\n    /**\n     * Returns true if the Xdebug is enabled.\n     */\n    public function hasXdebug(): bool\n    {\n        return $this->data['xdebug_enabled'];\n    }\n\n    public function getXdebugStatus(): string\n    {\n        return $this->data['xdebug_status'];\n    }\n\n    /**\n     * Returns true if the function xdebug_info is available.\n     */\n    public function hasXdebugInfo(): bool\n    {\n        return \\function_exists('xdebug_info');\n    }\n\n    /**\n     * Returns true if APCu is enabled.\n     */\n    public function hasApcu(): bool\n    {\n        return $this->data['apcu_enabled'];\n    }\n\n    public function getApcuStatus(): string\n    {\n        return $this->data['apcu_status'];\n    }\n\n    /**\n     * Returns true if Zend OPcache is enabled.\n     */\n    public function hasZendOpcache(): bool\n    {\n        return $this->data['zend_opcache_enabled'];\n    }\n\n    public function getZendOpcacheStatus(): string\n    {\n        return $this->data['zend_opcache_status'];\n    }\n\n    public function getBundles(): array|Data\n    {\n        return $this->data['bundles'];\n    }\n\n    /**\n     * Gets the PHP SAPI name.\n     */\n    public function getSapiName(): string\n    {\n        return $this->data['sapi_name'];\n    }\n\n    public function getRunnerClass(): ?string\n    {\n        return $this->data['runner_class'];\n    }\n\n    public function getName(): string\n    {\n        return 'config';\n    }\n\n    private function determineSymfonyState(): string\n    {\n        $now = new \\DateTimeImmutable();\n        $eom = \\DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE)->modify('last day of this month');\n        $eol = \\DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE)->modify('last day of this month');\n\n        if ($now > $eol) {\n            $versionState = 'eol';\n        } elseif ($now > $eom) {\n            $versionState = 'eom';\n        } elseif ('' !== Kernel::EXTRA_VERSION) {\n            $versionState = 'dev';\n        } else {\n            $versionState = 'stable';\n        }\n\n        return $versionState;\n    }\n\n    private function determineRunnerClass(): ?string\n    {\n        $stack = debug_backtrace(\\DEBUG_BACKTRACE_IGNORE_ARGS);\n        for ($frame = end($stack); $frame; $frame = prev($stack)) {\n            if (!$class = $frame['class'] ?? null) {\n                continue;\n            }\n            if (is_a($class, RunnerInterface::class, true)) {\n                return $class;\n            }\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "DataCollector/DataCollector.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DataCollector;\n\nuse Symfony\\Component\\VarDumper\\Caster\\CutStub;\nuse Symfony\\Component\\VarDumper\\Caster\\ReflectionCaster;\nuse Symfony\\Component\\VarDumper\\Cloner\\ClonerInterface;\nuse Symfony\\Component\\VarDumper\\Cloner\\Data;\nuse Symfony\\Component\\VarDumper\\Cloner\\Stub;\nuse Symfony\\Component\\VarDumper\\Cloner\\VarCloner;\n\n/**\n * DataCollector.\n *\n * Children of this class must store the collected data in the data property.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n * @author Bernhard Schussek <bschussek@symfony.com>\n */\nabstract class DataCollector implements DataCollectorInterface\n{\n    protected array|Data $data = [];\n\n    private ClonerInterface $cloner;\n\n    /**\n     * Converts the variable into a serializable Data instance.\n     *\n     * This array can be displayed in the template using\n     * the VarDumper component.\n     */\n    protected function cloneVar(mixed $var): Data\n    {\n        if ($var instanceof Data) {\n            return $var;\n        }\n        if (!isset($this->cloner)) {\n            $this->cloner = new VarCloner();\n            $this->cloner->setMaxItems(-1);\n            $this->cloner->addCasters($this->getCasters());\n        }\n\n        return $this->cloner->cloneVar($var);\n    }\n\n    /**\n     * @return callable[] The casters to add to the cloner\n     */\n    protected function getCasters(): array\n    {\n        return [\n            '*' => static function ($v, array $a, Stub $s, $isNested) {\n                if (!$v instanceof Stub) {\n                    $b = $a;\n                    foreach ($a as $k => $v) {\n                        if (!\\is_object($v) || $v instanceof \\DateTimeInterface || $v instanceof Stub) {\n                            continue;\n                        }\n\n                        try {\n                            $a[$k] = $s = new CutStub($v);\n\n                            if ($b[$k] === $s) {\n                                // we've hit a non-typed reference\n                                $a[$k] = $v;\n                            }\n                        } catch (\\TypeError $e) {\n                            // we've hit a typed reference\n                        }\n                    }\n                }\n\n                return $a;\n            },\n        ] + ReflectionCaster::UNSET_CLOSURE_FILE_INFO;\n    }\n\n    public function __serialize(): array\n    {\n        return ['data' => $this->data];\n    }\n\n    public function __unserialize(array $data): void\n    {\n        $this->data = $data['data'] ?? $data[\"\\0*\\0data\"];\n    }\n\n    public function reset(): void\n    {\n        $this->data = [];\n    }\n}\n"
  },
  {
    "path": "DataCollector/DataCollectorInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DataCollector;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * DataCollectorInterface.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface DataCollectorInterface extends ResetInterface\n{\n    /**\n     * Collects data for the given Request and Response.\n     */\n    public function collect(Request $request, Response $response, ?\\Throwable $exception = null): void;\n\n    /**\n     * Returns the name of the collector.\n     */\n    public function getName(): string;\n}\n"
  },
  {
    "path": "DataCollector/DumpDataCollector.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DataCollector;\n\nuse Symfony\\Component\\ErrorHandler\\ErrorRenderer\\FileLinkFormatter;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\Stopwatch\\Stopwatch;\nuse Symfony\\Component\\VarDumper\\Cloner\\Data;\nuse Symfony\\Component\\VarDumper\\Cloner\\VarCloner;\nuse Symfony\\Component\\VarDumper\\Dumper\\CliDumper;\nuse Symfony\\Component\\VarDumper\\Dumper\\ContextProvider\\SourceContextProvider;\nuse Symfony\\Component\\VarDumper\\Dumper\\DataDumperInterface;\nuse Symfony\\Component\\VarDumper\\Dumper\\HtmlDumper;\nuse Symfony\\Component\\VarDumper\\Server\\Connection;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @final\n */\nclass DumpDataCollector extends DataCollector implements DataDumperInterface\n{\n    private string|FileLinkFormatter|false $fileLinkFormat;\n    private int $dataCount = 0;\n    private bool $isCollected = true;\n    private int $clonesCount = 0;\n    private int $clonesIndex = 0;\n    private array $rootRefs;\n    private string $charset;\n    private mixed $sourceContextProvider;\n    private bool $webMode;\n\n    public function __construct(\n        private ?Stopwatch $stopwatch = null,\n        string|FileLinkFormatter|null $fileLinkFormat = null,\n        ?string $charset = null,\n        private ?RequestStack $requestStack = null,\n        private DataDumperInterface|Connection|null $dumper = null,\n        ?bool $webMode = null,\n    ) {\n        $fileLinkFormat = $fileLinkFormat ?: \\ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');\n        $this->fileLinkFormat = $fileLinkFormat instanceof FileLinkFormatter && false === $fileLinkFormat->format('', 0) ? false : $fileLinkFormat;\n        $this->charset = $charset ?: \\ini_get('php.output_encoding') ?: \\ini_get('default_charset') ?: 'UTF-8';\n        $this->webMode = $webMode ?? !\\in_array(\\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true);\n\n        // All clones share these properties by reference:\n        $this->rootRefs = [\n            &$this->data,\n            &$this->dataCount,\n            &$this->isCollected,\n            &$this->clonesCount,\n        ];\n\n        $this->sourceContextProvider = $dumper instanceof Connection && isset($dumper->getContextProviders()['source']) ? $dumper->getContextProviders()['source'] : new SourceContextProvider($this->charset);\n    }\n\n    public function __clone()\n    {\n        $this->clonesIndex = ++$this->clonesCount;\n    }\n\n    public function dump(Data $data): ?string\n    {\n        $this->stopwatch?->start('dump');\n\n        ['name' => $name, 'file' => $file, 'line' => $line, 'file_excerpt' => $fileExcerpt] = $this->sourceContextProvider->getContext();\n\n        if (!$this->dumper || $this->dumper instanceof Connection && !$this->dumper->write($data)) {\n            $this->isCollected = false;\n        }\n\n        $context = $data->getContext();\n        $label = $context['label'] ?? '';\n        unset($context['label']);\n        $data = $data->withContext($context);\n\n        if ($this->dumper && !$this->dumper instanceof Connection) {\n            $this->doDump($this->dumper, $data, $name, $file, $line, $label);\n        }\n\n        if (!$this->dataCount) {\n            $this->data = [];\n        }\n        $this->data[] = compact('data', 'name', 'file', 'line', 'fileExcerpt', 'label');\n        ++$this->dataCount;\n\n        $this->stopwatch?->stop('dump');\n\n        return null;\n    }\n\n    public function collect(Request $request, Response $response, ?\\Throwable $exception = null): void\n    {\n        if (!$this->dataCount) {\n            $this->data = [];\n        }\n\n        // Sub-requests and programmatic calls stay in the collected profile.\n        if ($this->dumper || ($this->requestStack && $this->requestStack->getMainRequest() !== $request) || $request->isXmlHttpRequest() || $request->headers->has('Origin')) {\n            return;\n        }\n\n        // In all other conditions that remove the web debug toolbar, dumps are written on the output.\n        if (!$this->requestStack\n            || !$response->headers->has('X-Debug-Token')\n            || $response->isRedirection()\n            || ($response->headers->has('Content-Type') && !str_contains($response->headers->get('Content-Type') ?? '', 'html'))\n            || 'html' !== $request->getRequestFormat()\n            || false === strripos($response->getContent(), '</body>')\n        ) {\n            if ($response->headers->has('Content-Type') && str_contains($response->headers->get('Content-Type') ?? '', 'html')) {\n                $dumper = new HtmlDumper('php://output', $this->charset);\n            } else {\n                $dumper = new CliDumper('php://output', $this->charset);\n            }\n\n            $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);\n\n            foreach ($this->data as $dump) {\n                $this->doDump($dumper, $dump['data'], $dump['name'], $dump['file'], $dump['line'], $dump['label'] ?? '');\n            }\n        }\n    }\n\n    public function reset(): void\n    {\n        $this->stopwatch?->reset();\n        parent::reset();\n        $this->dataCount = 0;\n        $this->isCollected = true;\n        $this->clonesCount = 0;\n        $this->clonesIndex = 0;\n    }\n\n    public function __serialize(): array\n    {\n        if (!$this->dataCount) {\n            $this->data = [];\n        }\n\n        if ($this->clonesCount !== $this->clonesIndex) {\n            return [];\n        }\n\n        $this->data[] = $this->fileLinkFormat;\n        $this->data[] = $this->charset;\n        $this->dataCount = 0;\n        $this->isCollected = true;\n\n        return ['data' => $this->data];\n    }\n\n    public function __unserialize(array $data): void\n    {\n        $this->data = array_pop($data) ?? [];\n        $charset = array_pop($this->data);\n        $fileLinkFormat = array_pop($this->data);\n        $this->dataCount = \\count($this->data);\n        foreach ($this->data as $dump) {\n            if (!\\is_string($dump['name']) || !\\is_string($dump['file']) || !\\is_int($dump['line'])) {\n                throw new \\BadMethodCallException('Cannot unserialize '.__CLASS__);\n            }\n        }\n\n        self::__construct($this->stopwatch ?? null, \\is_string($fileLinkFormat) || $fileLinkFormat instanceof FileLinkFormatter ? $fileLinkFormat : null, \\is_string($charset) ? $charset : null);\n    }\n\n    public function getDumpsCount(): int\n    {\n        return $this->dataCount;\n    }\n\n    public function getDumps(string $format, int $maxDepthLimit = -1, int $maxItemsPerDepth = -1): array\n    {\n        $data = fopen('php://memory', 'r+');\n\n        if ('html' === $format) {\n            $dumper = new HtmlDumper($data, $this->charset);\n            $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);\n        } else {\n            throw new \\InvalidArgumentException(\\sprintf('Invalid dump format: \"%s\".', $format));\n        }\n        $dumps = [];\n\n        if (!$this->dataCount) {\n            return $this->data = [];\n        }\n\n        foreach ($this->data as $dump) {\n            $dumper->dump($dump['data']->withMaxDepth($maxDepthLimit)->withMaxItemsPerDepth($maxItemsPerDepth));\n            $dump['data'] = stream_get_contents($data, -1, 0);\n            ftruncate($data, 0);\n            rewind($data);\n            $dumps[] = $dump;\n        }\n\n        return $dumps;\n    }\n\n    public function getName(): string\n    {\n        return 'dump';\n    }\n\n    public function __destruct()\n    {\n        if (0 === $this->clonesCount-- && !$this->isCollected && $this->dataCount) {\n            $this->clonesCount = 0;\n            $this->isCollected = true;\n\n            $h = headers_list();\n            $i = \\count($h);\n            array_unshift($h, 'Content-Type: '.\\ini_get('default_mimetype'));\n            while (0 !== stripos($h[$i], 'Content-Type:')) {\n                --$i;\n            }\n\n            if ($this->webMode) {\n                $dumper = new HtmlDumper('php://output', $this->charset);\n            } else {\n                $dumper = new CliDumper('php://output', $this->charset);\n            }\n\n            $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);\n\n            foreach ($this->data as $i => $dump) {\n                $this->data[$i] = null;\n                $this->doDump($dumper, $dump['data'], $dump['name'], $dump['file'], $dump['line'], $dump['label'] ?? '');\n            }\n\n            $this->data = [];\n            $this->dataCount = 0;\n        }\n    }\n\n    private function doDump(DataDumperInterface $dumper, Data $data, string $name, string $file, int $line, string $label): void\n    {\n        if ($dumper instanceof CliDumper) {\n            $contextDumper = function ($name, $file, $line, $fmt, $label) {\n                $this->line = '' !== $label ? $this->style('meta', $label).' in ' : '';\n\n                if ($this instanceof HtmlDumper) {\n                    if ($file) {\n                        $s = $this->style('meta', '%s');\n                        $f = strip_tags($this->style('', $file));\n                        $name = strip_tags($this->style('', $name));\n                        if ($fmt && $link = \\is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : $fmt->format($file, $line)) {\n                            $name = \\sprintf('<a href=\"%s\" title=\"%s\">'.$s.'</a>', strip_tags($this->style('', $link)), $f, $name);\n                        } else {\n                            $name = \\sprintf('<abbr title=\"%s\">'.$s.'</abbr>', $f, $name);\n                        }\n                    } else {\n                        $name = $this->style('meta', $name);\n                    }\n                    $this->line .= $name.' on line '.$this->style('meta', $line).':';\n                } else {\n                    $this->line .= $this->style('meta', $name).' on line '.$this->style('meta', $line).':';\n                }\n                $this->dumpLine(0);\n            };\n            $contextDumper = $contextDumper->bindTo($dumper, $dumper);\n            $contextDumper($name, $file, $line, $this->fileLinkFormat, $label);\n        } else {\n            $cloner = new VarCloner();\n            $dumper->dump($cloner->cloneVar(('' !== $label ? $label.' in ' : '').$name.' on line '.$line.':'));\n        }\n        $dumper->dump($data);\n    }\n}\n"
  },
  {
    "path": "DataCollector/EventDataCollector.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DataCollector;\n\nuse Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcher;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\VarDumper\\Cloner\\Data;\nuse Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @see TraceableEventDispatcher\n *\n * @final\n */\nclass EventDataCollector extends DataCollector implements LateDataCollectorInterface\n{\n    /** @var iterable<EventDispatcherInterface> */\n    private iterable $dispatchers;\n    private ?Request $currentRequest = null;\n\n    /**\n     * @param iterable<EventDispatcherInterface>|EventDispatcherInterface|null $dispatchers\n     */\n    public function __construct(\n        iterable|EventDispatcherInterface|null $dispatchers = null,\n        private ?RequestStack $requestStack = null,\n        private string $defaultDispatcher = 'event_dispatcher',\n    ) {\n        if ($dispatchers instanceof EventDispatcherInterface) {\n            $dispatchers = [$this->defaultDispatcher => $dispatchers];\n        }\n        $this->dispatchers = $dispatchers ?? [];\n    }\n\n    public function collect(Request $request, Response $response, ?\\Throwable $exception = null): void\n    {\n        $this->currentRequest = $this->requestStack && $this->requestStack->getMainRequest() !== $request ? $request : null;\n        $this->data = [];\n    }\n\n    public function reset(): void\n    {\n        parent::reset();\n\n        foreach ($this->dispatchers as $dispatcher) {\n            if ($dispatcher instanceof ResetInterface) {\n                $dispatcher->reset();\n            }\n        }\n    }\n\n    public function lateCollect(): void\n    {\n        foreach ($this->dispatchers as $name => $dispatcher) {\n            if (!$dispatcher instanceof TraceableEventDispatcher) {\n                continue;\n            }\n\n            $this->setCalledListeners($dispatcher->getCalledListeners($this->currentRequest), $name);\n            $this->setNotCalledListeners($dispatcher->getNotCalledListeners($this->currentRequest), $name);\n            $this->setOrphanedEvents($dispatcher->getOrphanedEvents($this->currentRequest), $name);\n        }\n\n        $this->data = $this->cloneVar($this->data);\n    }\n\n    public function getData(): array|Data\n    {\n        return $this->data;\n    }\n\n    /**\n     * @see TraceableEventDispatcher\n     */\n    public function setCalledListeners(array $listeners, ?string $dispatcher = null): void\n    {\n        $this->data[$dispatcher ?? $this->defaultDispatcher]['called_listeners'] = $listeners;\n    }\n\n    /**\n     * @see TraceableEventDispatcher\n     */\n    public function getCalledListeners(?string $dispatcher = null): array|Data\n    {\n        return $this->data[$dispatcher ?? $this->defaultDispatcher]['called_listeners'] ?? [];\n    }\n\n    /**\n     * @see TraceableEventDispatcher\n     */\n    public function setNotCalledListeners(array $listeners, ?string $dispatcher = null): void\n    {\n        $this->data[$dispatcher ?? $this->defaultDispatcher]['not_called_listeners'] = $listeners;\n    }\n\n    /**\n     * @see TraceableEventDispatcher\n     */\n    public function getNotCalledListeners(?string $dispatcher = null): array|Data\n    {\n        return $this->data[$dispatcher ?? $this->defaultDispatcher]['not_called_listeners'] ?? [];\n    }\n\n    /**\n     * @param array $events An array of orphaned events\n     *\n     * @see TraceableEventDispatcher\n     */\n    public function setOrphanedEvents(array $events, ?string $dispatcher = null): void\n    {\n        $this->data[$dispatcher ?? $this->defaultDispatcher]['orphaned_events'] = $events;\n    }\n\n    /**\n     * @see TraceableEventDispatcher\n     */\n    public function getOrphanedEvents(?string $dispatcher = null): array|Data\n    {\n        return $this->data[$dispatcher ?? $this->defaultDispatcher]['orphaned_events'] ?? [];\n    }\n\n    public function getName(): string\n    {\n        return 'events';\n    }\n}\n"
  },
  {
    "path": "DataCollector/ExceptionDataCollector.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DataCollector;\n\nuse Symfony\\Component\\ErrorHandler\\Exception\\FlattenException;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @final\n */\nclass ExceptionDataCollector extends DataCollector\n{\n    public function collect(Request $request, Response $response, ?\\Throwable $exception = null): void\n    {\n        if (null !== $exception) {\n            $this->data = [\n                'exception' => FlattenException::createWithDataRepresentation($exception),\n            ];\n        }\n    }\n\n    public function hasException(): bool\n    {\n        return isset($this->data['exception']);\n    }\n\n    public function getException(): \\Exception|FlattenException\n    {\n        return $this->data['exception'];\n    }\n\n    public function getMessage(): string\n    {\n        return $this->data['exception']->getMessage();\n    }\n\n    public function getCode(): int|string\n    {\n        return $this->data['exception']->getCode();\n    }\n\n    public function getStatusCode(): int\n    {\n        return $this->data['exception']->getStatusCode();\n    }\n\n    public function getTrace(): array\n    {\n        return $this->data['exception']->getTrace();\n    }\n\n    public function getName(): string\n    {\n        return 'exception';\n    }\n}\n"
  },
  {
    "path": "DataCollector/LateDataCollectorInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DataCollector;\n\n/**\n * LateDataCollectorInterface.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface LateDataCollectorInterface\n{\n    /**\n     * Collects data as late as possible.\n     */\n    public function lateCollect(): void;\n}\n"
  },
  {
    "path": "DataCollector/LoggerDataCollector.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DataCollector;\n\nuse Symfony\\Component\\ErrorHandler\\Exception\\SilencedErrorContext;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Log\\DebugLoggerConfigurator;\nuse Symfony\\Component\\HttpKernel\\Log\\DebugLoggerInterface;\nuse Symfony\\Component\\VarDumper\\Cloner\\Data;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @final\n */\nclass LoggerDataCollector extends DataCollector implements LateDataCollectorInterface\n{\n    private ?DebugLoggerInterface $logger;\n    private ?Request $currentRequest = null;\n    private ?array $processedLogs = null;\n\n    public function __construct(\n        ?object $logger = null,\n        private ?string $containerPathPrefix = null,\n        private ?RequestStack $requestStack = null,\n    ) {\n        $this->logger = DebugLoggerConfigurator::getDebugLogger($logger);\n    }\n\n    public function collect(Request $request, Response $response, ?\\Throwable $exception = null): void\n    {\n        $this->currentRequest = $this->requestStack && $this->requestStack->getMainRequest() !== $request ? $request : null;\n    }\n\n    public function lateCollect(): void\n    {\n        if ($this->logger) {\n            $containerDeprecationLogs = $this->getContainerDeprecationLogs();\n            $this->data = $this->computeErrorsCount($containerDeprecationLogs);\n            // get compiler logs later (only when they are needed) to improve performance\n            $this->data['compiler_logs'] = [];\n            $this->data['compiler_logs_filepath'] = $this->containerPathPrefix.'Compiler.log';\n            $this->data['logs'] = $this->sanitizeLogs(array_merge($this->logger->getLogs($this->currentRequest), $containerDeprecationLogs));\n            $this->data = $this->cloneVar($this->data);\n        }\n        $this->currentRequest = null;\n    }\n\n    public function getLogs(): Data|array\n    {\n        return $this->data['logs'] ?? [];\n    }\n\n    public function getProcessedLogs(): array\n    {\n        if (null !== $this->processedLogs) {\n            return $this->processedLogs;\n        }\n\n        $rawLogs = $this->getLogs();\n        if ([] === $rawLogs) {\n            return $this->processedLogs = $rawLogs;\n        }\n\n        $logs = [];\n        foreach ($this->getLogs()->getValue() as $rawLog) {\n            $rawLogData = $rawLog->getValue();\n\n            if ($rawLogData['priority']->getValue() > 300) {\n                $logType = 'error';\n            } elseif (isset($rawLogData['scream']) && false === $rawLogData['scream']->getValue()) {\n                $logType = 'deprecation';\n            } elseif (isset($rawLogData['scream']) && true === $rawLogData['scream']->getValue()) {\n                $logType = 'silenced';\n            } else {\n                $logType = 'regular';\n            }\n\n            $logs[] = [\n                'type' => $logType,\n                'errorCount' => $rawLog['errorCount'] ?? 1,\n                'timestamp' => $rawLogData['timestamp_rfc3339']->getValue(),\n                'priority' => $rawLogData['priority']->getValue(),\n                'priorityName' => $rawLogData['priorityName']->getValue(),\n                'channel' => $rawLogData['channel']->getValue(),\n                'message' => $rawLogData['message'],\n                'context' => $rawLogData['context'],\n            ];\n        }\n\n        // sort logs from oldest to newest\n        usort($logs, static fn ($logA, $logB) => $logA['timestamp'] <=> $logB['timestamp']);\n\n        return $this->processedLogs = $logs;\n    }\n\n    public function getFilters(): array\n    {\n        $filters = [\n            'channel' => [],\n            'priority' => [\n                'Debug' => 100,\n                'Info' => 200,\n                'Notice' => 250,\n                'Warning' => 300,\n                'Error' => 400,\n                'Critical' => 500,\n                'Alert' => 550,\n                'Emergency' => 600,\n            ],\n        ];\n\n        $allChannels = [];\n        foreach ($this->getProcessedLogs() as $log) {\n            if ('' === trim($log['channel'] ?? '')) {\n                continue;\n            }\n\n            $allChannels[] = $log['channel'];\n        }\n        $channels = array_unique($allChannels);\n        sort($channels);\n        $filters['channel'] = $channels;\n\n        return $filters;\n    }\n\n    public function getPriorities(): Data|array\n    {\n        return $this->data['priorities'] ?? [];\n    }\n\n    public function countErrors(): int\n    {\n        return $this->data['error_count'] ?? 0;\n    }\n\n    public function countDeprecations(): int\n    {\n        return $this->data['deprecation_count'] ?? 0;\n    }\n\n    public function countWarnings(): int\n    {\n        return $this->data['warning_count'] ?? 0;\n    }\n\n    public function countScreams(): int\n    {\n        return $this->data['scream_count'] ?? 0;\n    }\n\n    public function getCompilerLogs(): Data\n    {\n        return $this->cloneVar($this->getContainerCompilerLogs($this->data['compiler_logs_filepath'] ?? null));\n    }\n\n    public function getName(): string\n    {\n        return 'logger';\n    }\n\n    private function getContainerDeprecationLogs(): array\n    {\n        if (null === $this->containerPathPrefix || !is_file($file = $this->containerPathPrefix.'Deprecations.log')) {\n            return [];\n        }\n\n        if ('' === $logContent = trim(file_get_contents($file))) {\n            return [];\n        }\n\n        $bootTime = filemtime($file);\n        $logs = [];\n        foreach (unserialize($logContent) as $log) {\n            $log['context'] = ['exception' => new SilencedErrorContext($log['type'], $log['file'], $log['line'], $log['trace'], $log['count'])];\n            $log['timestamp'] = $bootTime;\n            $log['timestamp_rfc3339'] = (new \\DateTimeImmutable())->setTimestamp($bootTime)->format(\\DateTimeInterface::RFC3339_EXTENDED);\n            $log['priority'] = 100;\n            $log['priorityName'] = 'DEBUG';\n            $log['channel'] = null;\n            $log['scream'] = false;\n            unset($log['type'], $log['file'], $log['line'], $log['trace'], $log['count']);\n            $logs[] = $log;\n        }\n\n        return $logs;\n    }\n\n    private function getContainerCompilerLogs(?string $compilerLogsFilepath = null): array\n    {\n        if (!$compilerLogsFilepath || !is_file($compilerLogsFilepath)) {\n            return [];\n        }\n\n        $logs = [];\n        foreach (file($compilerLogsFilepath, \\FILE_IGNORE_NEW_LINES) as $log) {\n            $log = explode(': ', $log, 2);\n            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])) {\n                $log = ['Unknown Compiler Pass', implode(': ', $log)];\n            }\n\n            $logs[$log[0]][] = ['message' => $log[1]];\n        }\n\n        return $logs;\n    }\n\n    private function sanitizeLogs(array $logs): array\n    {\n        $sanitizedLogs = [];\n        $silencedLogs = [];\n\n        foreach ($logs as $log) {\n            if (!$this->isSilencedOrDeprecationErrorLog($log)) {\n                $sanitizedLogs[] = $log;\n\n                continue;\n            }\n\n            $message = '_'.$log['message'];\n            $exception = $log['context']['exception'];\n\n            if ($exception instanceof SilencedErrorContext) {\n                if (isset($silencedLogs[$id = spl_object_id($exception)])) {\n                    continue;\n                }\n                $silencedLogs[$id] = true;\n\n                if (!isset($sanitizedLogs[$message])) {\n                    $sanitizedLogs[$message] = $log + [\n                        'errorCount' => 0,\n                        'scream' => true,\n                    ];\n                }\n                $sanitizedLogs[$message]['errorCount'] += $exception->count;\n\n                continue;\n            }\n\n            $errorId = hash('xxh128', \"{$exception->getSeverity()}/{$exception->getLine()}/{$exception->getFile()}\\0{$message}\", true);\n\n            if (isset($sanitizedLogs[$errorId])) {\n                ++$sanitizedLogs[$errorId]['errorCount'];\n            } else {\n                $log += [\n                    'errorCount' => 1,\n                    'scream' => false,\n                ];\n\n                $sanitizedLogs[$errorId] = $log;\n            }\n        }\n\n        return array_values($sanitizedLogs);\n    }\n\n    private function isSilencedOrDeprecationErrorLog(array $log): bool\n    {\n        if (!isset($log['context']['exception'])) {\n            return false;\n        }\n\n        $exception = $log['context']['exception'];\n\n        if ($exception instanceof SilencedErrorContext) {\n            return true;\n        }\n\n        if ($exception instanceof \\ErrorException && \\in_array($exception->getSeverity(), [\\E_DEPRECATED, \\E_USER_DEPRECATED], true)) {\n            return true;\n        }\n\n        return false;\n    }\n\n    private function computeErrorsCount(array $containerDeprecationLogs): array\n    {\n        $silencedLogs = [];\n        $count = [\n            'error_count' => $this->logger->countErrors($this->currentRequest),\n            'deprecation_count' => 0,\n            'warning_count' => 0,\n            'scream_count' => 0,\n            'priorities' => [],\n        ];\n\n        foreach ($this->logger->getLogs($this->currentRequest) as $log) {\n            if (isset($count['priorities'][$log['priority']])) {\n                ++$count['priorities'][$log['priority']]['count'];\n            } else {\n                $count['priorities'][$log['priority']] = [\n                    'count' => 1,\n                    'name' => $log['priorityName'],\n                ];\n            }\n            if ('WARNING' === $log['priorityName']) {\n                ++$count['warning_count'];\n            }\n\n            if ($this->isSilencedOrDeprecationErrorLog($log)) {\n                $exception = $log['context']['exception'];\n                if ($exception instanceof SilencedErrorContext) {\n                    if (isset($silencedLogs[$id = spl_object_id($exception)])) {\n                        continue;\n                    }\n                    $silencedLogs[$id] = true;\n                    $count['scream_count'] += $exception->count;\n                } else {\n                    ++$count['deprecation_count'];\n                }\n            }\n        }\n\n        foreach ($containerDeprecationLogs as $deprecationLog) {\n            $count['deprecation_count'] += $deprecationLog['context']['exception']->count;\n        }\n\n        ksort($count['priorities']);\n\n        return $count;\n    }\n}\n"
  },
  {
    "path": "DataCollector/MemoryDataCollector.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DataCollector;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @final\n */\nclass MemoryDataCollector extends DataCollector implements LateDataCollectorInterface\n{\n    public function __construct()\n    {\n        $this->reset();\n    }\n\n    public function collect(Request $request, Response $response, ?\\Throwable $exception = null): void\n    {\n        $this->updateMemoryUsage();\n    }\n\n    public function reset(): void\n    {\n        $this->data = [\n            'memory' => 0,\n            'memory_limit' => $this->convertToBytes(\\ini_get('memory_limit')),\n        ];\n    }\n\n    public function lateCollect(): void\n    {\n        $this->updateMemoryUsage();\n    }\n\n    public function getMemory(): int\n    {\n        return $this->data['memory'];\n    }\n\n    public function getMemoryLimit(): int|float\n    {\n        return $this->data['memory_limit'];\n    }\n\n    public function updateMemoryUsage(): void\n    {\n        $this->data['memory'] = memory_get_peak_usage(true);\n    }\n\n    public function getName(): string\n    {\n        return 'memory';\n    }\n\n    private function convertToBytes(string $memoryLimit): int|float\n    {\n        if ('-1' === $memoryLimit) {\n            return -1;\n        }\n\n        $memoryLimit = strtolower($memoryLimit);\n        $max = strtolower(ltrim($memoryLimit, '+'));\n        if (str_starts_with($max, '0x')) {\n            $max = \\intval($max, 16);\n        } elseif (str_starts_with($max, '0')) {\n            $max = \\intval($max, 8);\n        } else {\n            $max = (int) $max;\n        }\n\n        switch (substr($memoryLimit, -1)) {\n            case 't': $max *= 1024;\n                // no break\n            case 'g': $max *= 1024;\n                // no break\n            case 'm': $max *= 1024;\n                // no break\n            case 'k': $max *= 1024;\n        }\n\n        return $max;\n    }\n}\n"
  },
  {
    "path": "DataCollector/RequestDataCollector.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DataCollector;\n\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpFoundation\\Cookie;\nuse Symfony\\Component\\HttpFoundation\\ParameterBag;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpFoundation\\Session\\SessionBagInterface;\nuse Symfony\\Component\\HttpFoundation\\Session\\SessionInterface;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\nuse Symfony\\Component\\Process\\Process;\nuse Symfony\\Component\\VarDumper\\Cloner\\Data;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @final\n */\nclass RequestDataCollector extends DataCollector implements EventSubscriberInterface, LateDataCollectorInterface\n{\n    /**\n     * @var \\SplObjectStorage<Request, callable>\n     */\n    private \\SplObjectStorage $controllers;\n    private array $sessionUsages = [];\n\n    public function __construct(\n        private ?RequestStack $requestStack = null,\n    ) {\n        $this->controllers = new \\SplObjectStorage();\n    }\n\n    public function collect(Request $request, Response $response, ?\\Throwable $exception = null): void\n    {\n        // attributes are serialized and as they can be anything, they need to be converted to strings.\n        $attributes = [];\n        $route = '';\n        foreach ($request->attributes->all() as $key => $value) {\n            if ('_route' === $key) {\n                $route = \\is_object($value) ? $value->getPath() : $value;\n                $attributes[$key] = $route;\n            } else {\n                $attributes[$key] = $value;\n            }\n        }\n\n        $content = $request->getContent();\n\n        $sessionMetadata = [];\n        $sessionAttributes = [];\n        $flashes = [];\n        if (!$request->attributes->getBoolean('_stateless') && $request->hasSession()) {\n            $session = $request->getSession();\n            if ($session->isStarted()) {\n                $sessionMetadata['Created'] = date(\\DATE_RFC822, $session->getMetadataBag()->getCreated());\n                $sessionMetadata['Last used'] = date(\\DATE_RFC822, $session->getMetadataBag()->getLastUsed());\n                $sessionMetadata['Lifetime'] = $session->getMetadataBag()->getLifetime();\n                $sessionAttributes = $session->all();\n                $flashes = $session->getFlashBag()->peekAll();\n            }\n        }\n\n        $statusCode = $response->getStatusCode();\n\n        $responseCookies = [];\n        foreach ($response->headers->getCookies() as $cookie) {\n            $responseCookies[$cookie->getName()] = $cookie;\n        }\n\n        $dotenvVars = [];\n        foreach (explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? $_ENV['SYMFONY_DOTENV_VARS'] ?? '') as $name) {\n            if ('' !== $name && isset($_ENV[$name])) {\n                $dotenvVars[$name] = $_ENV[$name];\n            }\n        }\n\n        $this->data = [\n            'method' => $request->getMethod(),\n            'format' => $request->getRequestFormat(),\n            'content_type' => $response->headers->get('Content-Type', 'text/html'),\n            'status_text' => Response::$statusTexts[$statusCode] ?? '',\n            'status_code' => $statusCode,\n            'request_query' => $request->query->all(),\n            'request_request' => $request->request->all(),\n            'request_files' => $request->files->all(),\n            'request_headers' => $request->headers->all(),\n            'request_server' => $request->server->all(),\n            'request_cookies' => $request->cookies->all(),\n            'request_attributes' => $attributes,\n            'route' => $route,\n            'response_headers' => $response->headers->all(),\n            'response_cookies' => $responseCookies,\n            'session_metadata' => $sessionMetadata,\n            'session_attributes' => $sessionAttributes,\n            'session_usages' => array_values($this->sessionUsages),\n            'stateless_check' => $this->requestStack?->getMainRequest()?->attributes->get('_stateless') ?? false,\n            'flashes' => $flashes,\n            'path_info' => $request->getPathInfo(),\n            'controller' => 'n/a',\n            'locale' => $request->getLocale(),\n            'dotenv_vars' => $dotenvVars,\n        ];\n\n        if (isset($this->data['request_headers']['php-auth-pw'])) {\n            $this->data['request_headers']['php-auth-pw'] = '******';\n        }\n\n        if (isset($this->data['request_server']['PHP_AUTH_PW'])) {\n            $this->data['request_server']['PHP_AUTH_PW'] = '******';\n        }\n\n        if (isset($this->data['request_request']['_password'])) {\n            $encodedPassword = rawurlencode($this->data['request_request']['_password']);\n            $content = str_replace('_password='.$encodedPassword, '_password=******', $content);\n            $this->data['request_request']['_password'] = '******';\n        }\n\n        $this->data['content'] = $content;\n\n        $this->data['curlCommand'] = $this->computeCurlCommand($request, $content);\n\n        foreach ($this->data as $key => $value) {\n            if (!\\is_array($value)) {\n                continue;\n            }\n            if ('request_headers' === $key || 'response_headers' === $key) {\n                $this->data[$key] = array_map(static fn ($v) => isset($v[0]) && !isset($v[1]) ? $v[0] : $v, $value);\n            }\n        }\n\n        if (isset($this->controllers[$request])) {\n            $this->data['controller'] = $this->parseController($this->controllers[$request]);\n            unset($this->controllers[$request]);\n        }\n\n        if ($request->attributes->has('_redirected') && $redirectCookie = $request->cookies->get('sf_redirect')) {\n            $this->data['redirect'] = json_decode($redirectCookie, true);\n\n            $response->headers->clearCookie('sf_redirect');\n        }\n\n        if ($response->isRedirect()) {\n            $response->headers->setCookie(new Cookie(\n                'sf_redirect',\n                json_encode([\n                    'token' => $response->headers->get('x-debug-token'),\n                    'route' => $request->attributes->get('_route', 'n/a'),\n                    'method' => $request->getMethod(),\n                    'controller' => $this->parseController($request->attributes->get('_controller')),\n                    'status_code' => $statusCode,\n                    'status_text' => Response::$statusTexts[$statusCode],\n                ]),\n                0, '/', null, $request->isSecure(), true, false, 'lax'\n            ));\n        }\n\n        $this->data['identifier'] = $this->data['route'] ?: (\\is_array($this->data['controller']) ? $this->data['controller']['class'].'::'.$this->data['controller']['method'].'()' : $this->data['controller']);\n\n        if ($response->headers->has('x-previous-debug-token')) {\n            $this->data['forward_token'] = $response->headers->get('x-previous-debug-token');\n        }\n    }\n\n    public function lateCollect(): void\n    {\n        $this->data = $this->cloneVar($this->data);\n    }\n\n    public function reset(): void\n    {\n        parent::reset();\n        $this->controllers = new \\SplObjectStorage();\n        $this->sessionUsages = [];\n    }\n\n    public function getMethod(): string\n    {\n        return $this->data['method'];\n    }\n\n    public function getPathInfo(): string\n    {\n        return $this->data['path_info'];\n    }\n\n    public function getRequestRequest(): ParameterBag\n    {\n        return new ParameterBag($this->data['request_request']->getValue());\n    }\n\n    public function getRequestQuery(): ParameterBag\n    {\n        return new ParameterBag($this->data['request_query']->getValue());\n    }\n\n    public function getRequestFiles(): ParameterBag\n    {\n        return new ParameterBag($this->data['request_files']->getValue());\n    }\n\n    public function getRequestHeaders(): ParameterBag\n    {\n        return new ParameterBag($this->data['request_headers']->getValue());\n    }\n\n    public function getRequestServer(bool $raw = false): ParameterBag\n    {\n        return new ParameterBag($this->data['request_server']->getValue($raw));\n    }\n\n    public function getRequestCookies(bool $raw = false): ParameterBag\n    {\n        return new ParameterBag($this->data['request_cookies']->getValue($raw));\n    }\n\n    public function getRequestAttributes(): ParameterBag\n    {\n        return new ParameterBag($this->data['request_attributes']->getValue());\n    }\n\n    public function getResponseHeaders(): ParameterBag\n    {\n        return new ParameterBag($this->data['response_headers']->getValue());\n    }\n\n    public function getResponseCookies(): ParameterBag\n    {\n        return new ParameterBag($this->data['response_cookies']->getValue());\n    }\n\n    public function getSessionMetadata(): array\n    {\n        return $this->data['session_metadata']->getValue();\n    }\n\n    public function getSessionAttributes(): array\n    {\n        return $this->data['session_attributes']->getValue();\n    }\n\n    public function getStatelessCheck(): bool\n    {\n        return $this->data['stateless_check'];\n    }\n\n    public function getSessionUsages(): Data|array\n    {\n        return $this->data['session_usages'];\n    }\n\n    public function getFlashes(): array\n    {\n        return $this->data['flashes']->getValue();\n    }\n\n    /**\n     * @return string|resource\n     */\n    public function getContent()\n    {\n        return $this->data['content'];\n    }\n\n    public function isJsonRequest(): bool\n    {\n        return 1 === preg_match('{^application/(?:\\w+\\++)*json$}i', $this->data['request_headers']['content-type']);\n    }\n\n    public function getPrettyJson(): ?string\n    {\n        $decoded = json_decode($this->getContent());\n\n        return \\JSON_ERROR_NONE === json_last_error() ? json_encode($decoded, \\JSON_PRETTY_PRINT) : null;\n    }\n\n    public function getContentType(): string\n    {\n        return $this->data['content_type'];\n    }\n\n    public function getStatusText(): string\n    {\n        return $this->data['status_text'];\n    }\n\n    public function getStatusCode(): int\n    {\n        return $this->data['status_code'];\n    }\n\n    public function getFormat(): string\n    {\n        return $this->data['format'];\n    }\n\n    public function getLocale(): string\n    {\n        return $this->data['locale'];\n    }\n\n    public function getDotenvVars(): ParameterBag\n    {\n        return new ParameterBag($this->data['dotenv_vars']->getValue());\n    }\n\n    /**\n     * Gets the route name.\n     *\n     * The _route request attributes is automatically set by the Router Matcher.\n     */\n    public function getRoute(): string\n    {\n        return $this->data['route'];\n    }\n\n    public function getIdentifier(): string\n    {\n        return $this->data['identifier'];\n    }\n\n    /**\n     * Gets the route parameters.\n     *\n     * The _route_params request attributes is automatically set by the RouterListener.\n     */\n    public function getRouteParams(): array\n    {\n        return isset($this->data['request_attributes']['_route_params']) ? $this->data['request_attributes']['_route_params']->getValue() : [];\n    }\n\n    /**\n     * Gets the parsed controller.\n     *\n     * @return array|string|Data The controller as a string or array of data\n     *                           with keys 'class', 'method', 'file' and 'line'\n     */\n    public function getController(): array|string|Data\n    {\n        return $this->data['controller'];\n    }\n\n    /**\n     * Gets the previous request attributes.\n     *\n     * @return array|Data|false A legacy array of data from the previous redirection response\n     *                          or false otherwise\n     */\n    public function getRedirect(): array|Data|false\n    {\n        return $this->data['redirect'] ?? false;\n    }\n\n    public function getForwardToken(): ?string\n    {\n        return $this->data['forward_token'] ?? null;\n    }\n\n    public function onKernelController(ControllerEvent $event): void\n    {\n        $this->controllers[$event->getRequest()] = $event->getController();\n    }\n\n    public function onKernelResponse(ResponseEvent $event): void\n    {\n        if (!$event->isMainRequest()) {\n            return;\n        }\n\n        if ($event->getRequest()->cookies->has('sf_redirect')) {\n            $event->getRequest()->attributes->set('_redirected', true);\n        }\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        return [\n            KernelEvents::CONTROLLER => 'onKernelController',\n            KernelEvents::RESPONSE => 'onKernelResponse',\n        ];\n    }\n\n    public function getName(): string\n    {\n        return 'request';\n    }\n\n    public function collectSessionUsage(): void\n    {\n        $trace = debug_backtrace(\\DEBUG_BACKTRACE_IGNORE_ARGS);\n\n        $traceEndIndex = \\count($trace) - 1;\n        for ($i = $traceEndIndex; $i > 0; --$i) {\n            if (null !== ($class = $trace[$i]['class'] ?? null) && (is_subclass_of($class, SessionInterface::class) || is_subclass_of($class, SessionBagInterface::class))) {\n                $traceEndIndex = $i;\n                break;\n            }\n        }\n\n        if ((\\count($trace) - 1) === $traceEndIndex) {\n            return;\n        }\n\n        // Remove part of the backtrace that belongs to session only\n        array_splice($trace, 0, $traceEndIndex);\n\n        // Merge identical backtraces generated by internal call reports\n        $name = \\sprintf('%s:%s', $trace[1]['class'] ?? $trace[0]['file'], $trace[0]['line']);\n        if (!\\array_key_exists($name, $this->sessionUsages)) {\n            $this->sessionUsages[$name] = [\n                'name' => $name,\n                'file' => $trace[0]['file'],\n                'line' => $trace[0]['line'],\n                'trace' => $trace,\n            ];\n        }\n    }\n\n    /**\n     * @return array|string An array of controller data or a simple string\n     */\n    private function parseController(array|object|string|null $controller): array|string\n    {\n        if (\\is_string($controller) && str_contains($controller, '::')) {\n            $controller = explode('::', $controller);\n        }\n\n        if (\\is_array($controller)) {\n            try {\n                $r = new \\ReflectionMethod($controller[0], $controller[1]);\n\n                return [\n                    'class' => \\is_object($controller[0]) ? get_debug_type($controller[0]) : $controller[0],\n                    'method' => $controller[1],\n                    'file' => $r->getFileName(),\n                    'line' => $r->getStartLine(),\n                ];\n            } catch (\\ReflectionException) {\n                if (\\is_callable($controller)) {\n                    // using __call or  __callStatic\n                    return [\n                        'class' => \\is_object($controller[0]) ? get_debug_type($controller[0]) : $controller[0],\n                        'method' => $controller[1],\n                        'file' => 'n/a',\n                        'line' => 'n/a',\n                    ];\n                }\n            }\n        }\n\n        if ($controller instanceof \\Closure) {\n            $r = new \\ReflectionFunction($controller);\n\n            $controller = [\n                'class' => $r->getName(),\n                'method' => null,\n                'file' => $r->getFileName(),\n                'line' => $r->getStartLine(),\n            ];\n\n            if ($r->isAnonymous()) {\n                return $controller;\n            }\n            $controller['method'] = $r->name;\n\n            if ($class = $r->getClosureCalledClass()) {\n                $controller['class'] = $class->name;\n            } else {\n                return $r->name;\n            }\n\n            return $controller;\n        }\n\n        if (\\is_object($controller)) {\n            $r = new \\ReflectionClass($controller);\n\n            return [\n                'class' => $r->getName(),\n                'method' => null,\n                'file' => $r->getFileName(),\n                'line' => $r->getStartLine(),\n            ];\n        }\n\n        return \\is_string($controller) ? $controller : 'n/a';\n    }\n\n    private function computeCurlCommand(Request $request, ?string $content): string\n    {\n        $command = ['curl', '--compressed'];\n\n        $method = $request->getMethod();\n\n        if (Request::METHOD_HEAD === $method) {\n            $command[] = '--head';\n        } elseif (Request::METHOD_GET !== $method) {\n            $command[] = \\sprintf('--request %s', $method);\n        }\n\n        $command[] = \\sprintf('--url %s', escapeshellarg($request->getUri()));\n\n        foreach ($request->headers->all() as $name => $values) {\n            if (\\in_array(strtolower($name), ['host', 'cookie'], true)) {\n                continue;\n            }\n\n            $command[] = '--header '.escapeshellarg(ucwords($name, '-').': '.implode(', ', $values));\n        }\n\n        if ($request->cookies->all()) {\n            $cookies = [];\n            foreach ($request->cookies->all() as $name => $value) {\n                $cookies[] = urlencode($name).'='.urlencode($value);\n            }\n            $command[] = '--cookie '.escapeshellarg(implode('; ', $cookies));\n        }\n\n        if ($content && \\in_array($method, [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_PATCH, Request::METHOD_DELETE], true)) {\n            $command[] = '--data-raw '.$this->escapePayload($content);\n        }\n\n        return implode(\" \\\\\\n  \", $command);\n    }\n\n    public function getCurlCommand(): string\n    {\n        return $this->data['curlCommand'] ?? '';\n    }\n\n    private function escapePayload(string $payload): string\n    {\n        static $useProcess;\n\n        if ($useProcess ??= \\function_exists('proc_open') && class_exists(Process::class)) {\n            return substr((new Process(['', $payload]))->getCommandLine(), 3);\n        }\n\n        if ('\\\\' === \\DIRECTORY_SEPARATOR) {\n            return '\"'.str_replace('\"', '\"\"', $payload).'\"';\n        }\n\n        return \"'\".str_replace(\"'\", \"'\\\\''\", $payload).\"'\";\n    }\n}\n"
  },
  {
    "path": "DataCollector/RouterDataCollector.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DataCollector;\n\nuse Symfony\\Component\\HttpFoundation\\RedirectResponse;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerEvent;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass RouterDataCollector extends DataCollector\n{\n    /**\n     * @var \\SplObjectStorage<Request, callable>\n     */\n    protected \\SplObjectStorage $controllers;\n\n    public function __construct()\n    {\n        $this->reset();\n    }\n\n    /**\n     * @final\n     */\n    public function collect(Request $request, Response $response, ?\\Throwable $exception = null): void\n    {\n        if ($response instanceof RedirectResponse) {\n            $this->data['redirect'] = true;\n            $this->data['url'] = $response->getTargetUrl();\n\n            if ($this->controllers->offsetExists($request)) {\n                $this->data['route'] = $this->guessRoute($request, $this->controllers[$request]);\n            }\n        }\n\n        unset($this->controllers[$request]);\n    }\n\n    public function reset(): void\n    {\n        $this->controllers = new \\SplObjectStorage();\n\n        $this->data = [\n            'redirect' => false,\n            'url' => null,\n            'route' => null,\n        ];\n    }\n\n    protected function guessRoute(Request $request, string|object|array $controller): string\n    {\n        return 'n/a';\n    }\n\n    /**\n     * Remembers the controller associated to each request.\n     */\n    public function onKernelController(ControllerEvent $event): void\n    {\n        $this->controllers[$event->getRequest()] = $event->getController();\n    }\n\n    /**\n     * @return bool Whether this request will result in a redirect\n     */\n    public function getRedirect(): bool\n    {\n        return $this->data['redirect'];\n    }\n\n    public function getTargetUrl(): ?string\n    {\n        return $this->data['url'];\n    }\n\n    public function getTargetRoute(): ?string\n    {\n        return $this->data['route'];\n    }\n\n    public function getName(): string\n    {\n        return 'router';\n    }\n}\n"
  },
  {
    "path": "DataCollector/TimeDataCollector.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DataCollector;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\KernelInterface;\nuse Symfony\\Component\\Stopwatch\\Stopwatch;\nuse Symfony\\Component\\Stopwatch\\StopwatchEvent;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @final\n */\nclass TimeDataCollector extends DataCollector implements LateDataCollectorInterface\n{\n    public function __construct(\n        private readonly ?KernelInterface $kernel = null,\n        private readonly ?Stopwatch $stopwatch = null,\n    ) {\n        $this->data = ['events' => [], 'stopwatch_installed' => false, 'start_time' => 0];\n    }\n\n    public function collect(Request $request, Response $response, ?\\Throwable $exception = null): void\n    {\n        if (null !== $this->kernel) {\n            $startTime = $this->kernel->getStartTime();\n        } else {\n            $startTime = $request->server->get('REQUEST_TIME_FLOAT');\n        }\n\n        $this->data = [\n            'token' => $request->attributes->get('_stopwatch_token'),\n            'start_time' => $startTime * 1000,\n            'events' => [],\n            'stopwatch_installed' => class_exists(Stopwatch::class, false),\n        ];\n    }\n\n    public function reset(): void\n    {\n        $this->data = ['events' => [], 'stopwatch_installed' => false, 'start_time' => 0];\n\n        $this->stopwatch?->reset();\n    }\n\n    public function lateCollect(): void\n    {\n        if (null !== $this->stopwatch && isset($this->data['token'])) {\n            $this->setEvents($this->stopwatch->getSectionEvents($this->data['token']));\n        }\n        unset($this->data['token']);\n    }\n\n    /**\n     * @param StopwatchEvent[] $events The request events\n     */\n    public function setEvents(array $events): void\n    {\n        foreach ($events as $event) {\n            $event->ensureStopped();\n        }\n\n        $this->data['events'] = $events;\n    }\n\n    /**\n     * @return StopwatchEvent[]\n     */\n    public function getEvents(): array\n    {\n        return $this->data['events'];\n    }\n\n    /**\n     * Gets the request elapsed time.\n     */\n    public function getDuration(): float\n    {\n        if (!isset($this->data['events']['__section__'])) {\n            return 0;\n        }\n\n        $lastEvent = $this->data['events']['__section__'];\n\n        return $lastEvent->getOrigin() + $lastEvent->getDuration() - $this->getStartTime();\n    }\n\n    /**\n     * Gets the initialization time.\n     *\n     * This is the time spent until the beginning of the request handling.\n     */\n    public function getInitTime(): float\n    {\n        if (!isset($this->data['events']['__section__'])) {\n            return 0;\n        }\n\n        return $this->data['events']['__section__']->getOrigin() - $this->getStartTime();\n    }\n\n    public function getStartTime(): float\n    {\n        return $this->data['start_time'];\n    }\n\n    public function isStopwatchInstalled(): bool\n    {\n        return $this->data['stopwatch_installed'];\n    }\n\n    public function getName(): string\n    {\n        return 'time';\n    }\n}\n"
  },
  {
    "path": "Debug/ErrorHandlerConfigurator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Debug;\n\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\ErrorHandler\\ErrorHandler;\n\n/**\n * Configures the error handler.\n *\n * @final\n *\n * @internal\n */\nclass ErrorHandlerConfigurator\n{\n    private array|int|null $levels;\n    private ?int $throwAt;\n\n    /**\n     * @param array|int|null $levels  An array map of E_* to LogLevel::* or an integer bit field of E_* constants\n     * @param int|null       $throwAt Thrown errors in a bit field of E_* constants, or null to keep the current value\n     * @param bool           $scream  Enables/disables screaming mode, where even silenced errors are logged\n     * @param bool           $scope   Enables/disables scoping mode\n     */\n    public function __construct(\n        private ?LoggerInterface $logger = null,\n        array|int|null $levels = \\E_ALL,\n        ?int $throwAt = \\E_ALL,\n        private bool $scream = true,\n        private bool $scope = true,\n        private ?LoggerInterface $deprecationLogger = null,\n    ) {\n        $this->levels = $levels ?? \\E_ALL;\n        $this->throwAt = \\is_int($throwAt) ? $throwAt : (null === $throwAt ? null : ($throwAt ? \\E_ALL : null));\n    }\n\n    /**\n     * Configures the error handler.\n     */\n    public function configure(ErrorHandler $handler): void\n    {\n        if ($this->logger || $this->deprecationLogger) {\n            $this->setDefaultLoggers($handler);\n            if (\\is_array($this->levels)) {\n                $levels = 0;\n                foreach ($this->levels as $type => $log) {\n                    $levels |= $type;\n                }\n            } else {\n                $levels = $this->levels;\n            }\n\n            if ($this->scream) {\n                $handler->screamAt($levels);\n            }\n            if ($this->scope) {\n                $handler->scopeAt($levels & ~\\E_USER_DEPRECATED & ~\\E_DEPRECATED);\n            } else {\n                $handler->scopeAt(0, true);\n            }\n            $this->logger = $this->deprecationLogger = $this->levels = null;\n        }\n        if (null !== $this->throwAt) {\n            $handler->throwAt($this->throwAt, true);\n        }\n    }\n\n    private function setDefaultLoggers(ErrorHandler $handler): void\n    {\n        if (\\is_array($this->levels)) {\n            $levelsDeprecatedOnly = [];\n            $levelsWithoutDeprecated = [];\n            foreach ($this->levels as $type => $log) {\n                if (\\E_DEPRECATED == $type || \\E_USER_DEPRECATED == $type) {\n                    $levelsDeprecatedOnly[$type] = $log;\n                } else {\n                    $levelsWithoutDeprecated[$type] = $log;\n                }\n            }\n        } else {\n            $levelsDeprecatedOnly = $this->levels & (\\E_DEPRECATED | \\E_USER_DEPRECATED);\n            $levelsWithoutDeprecated = $this->levels & ~\\E_DEPRECATED & ~\\E_USER_DEPRECATED;\n        }\n\n        $defaultLoggerLevels = $this->levels;\n        if ($this->deprecationLogger && $levelsDeprecatedOnly) {\n            $handler->setDefaultLogger($this->deprecationLogger, $levelsDeprecatedOnly);\n            $defaultLoggerLevels = $levelsWithoutDeprecated;\n        }\n\n        if ($this->logger && $defaultLoggerLevels) {\n            $handler->setDefaultLogger($this->logger, $defaultLoggerLevels);\n        }\n    }\n}\n"
  },
  {
    "path": "Debug/TraceableEventDispatcher.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Debug;\n\nuse Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcher as BaseTraceableEventDispatcher;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\n\n/**\n * Collects some data about event listeners.\n *\n * This event dispatcher delegates the dispatching to another one.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass TraceableEventDispatcher extends BaseTraceableEventDispatcher\n{\n    protected function beforeDispatch(string $eventName, object $event): void\n    {\n        if ($this->disabled?->__invoke()) {\n            return;\n        }\n        switch ($eventName) {\n            case KernelEvents::REQUEST:\n                $event->getRequest()->attributes->set('_stopwatch_token', bin2hex(random_bytes(3)));\n                $this->stopwatch->openSection();\n                break;\n            case KernelEvents::VIEW:\n            case KernelEvents::RESPONSE:\n                // stop only if a controller has been executed\n                if ($this->stopwatch->isStarted('controller')) {\n                    $this->stopwatch->stop('controller');\n                }\n                break;\n            case KernelEvents::TERMINATE:\n                $sectionId = $event->getRequest()->attributes->get('_stopwatch_token');\n                if (null === $sectionId) {\n                    break;\n                }\n                // There is a very special case when using built-in AppCache class as kernel wrapper, in the case\n                // of an ESI request leading to a `stale` response [B]  inside a `fresh` cached response [A].\n                // In this case, `$token` contains the [B] debug token, but the  open `stopwatch` section ID\n                // is equal to the [A] debug token. Trying to reopen section with the [B] token throws an exception\n                // which must be caught.\n                try {\n                    $this->stopwatch->openSection($sectionId);\n                } catch (\\LogicException) {\n                }\n                break;\n        }\n    }\n\n    protected function afterDispatch(string $eventName, object $event): void\n    {\n        if ($this->disabled?->__invoke()) {\n            return;\n        }\n        switch ($eventName) {\n            case KernelEvents::CONTROLLER_ARGUMENTS:\n                $this->stopwatch->start('controller', 'section');\n                break;\n            case KernelEvents::RESPONSE:\n                $sectionId = $event->getRequest()->attributes->get('_stopwatch_token');\n                if (null === $sectionId) {\n                    break;\n                }\n                try {\n                    $this->stopwatch->stopSection($sectionId);\n                } catch (\\LogicException) {\n                    // The stop watch service might have been reset in the meantime\n                }\n                break;\n            case KernelEvents::TERMINATE:\n                // In the special case described in the `preDispatch` method above, the `$token` section\n                // does not exist, then closing it throws an exception which must be caught.\n                $sectionId = $event->getRequest()->attributes->get('_stopwatch_token');\n                if (null === $sectionId) {\n                    break;\n                }\n                try {\n                    $this->stopwatch->stopSection($sectionId);\n                } catch (\\LogicException) {\n                }\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "Debug/VirtualRequestStack.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Debug;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\n\n/**\n * A stack able to deal with virtual requests.\n *\n * @internal\n *\n * @author Jules Pietri <jules@heahprod.com>\n */\nfinal class VirtualRequestStack extends RequestStack\n{\n    public function __construct(\n        private readonly RequestStack $decorated,\n    ) {\n    }\n\n    public function push(Request $request): void\n    {\n        if ($request->attributes->has('_virtual_type')) {\n            if ($this->decorated->getCurrentRequest()) {\n                throw new \\LogicException('Cannot mix virtual and HTTP requests.');\n            }\n\n            parent::push($request);\n\n            return;\n        }\n\n        $this->decorated->push($request);\n    }\n\n    public function pop(): ?Request\n    {\n        return $this->decorated->pop() ?? parent::pop();\n    }\n\n    public function getCurrentRequest(): ?Request\n    {\n        return $this->decorated->getCurrentRequest() ?? parent::getCurrentRequest();\n    }\n\n    public function getMainRequest(): ?Request\n    {\n        return $this->decorated->getMainRequest() ?? parent::getMainRequest();\n    }\n\n    public function getParentRequest(): ?Request\n    {\n        return $this->decorated->getParentRequest() ?? parent::getParentRequest();\n    }\n}\n"
  },
  {
    "path": "DependencyInjection/ConfigurableExtension.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Extension\\Extension;\n\n/**\n * This extension sub-class provides first-class integration with the\n * Config/Definition Component.\n *\n * You can use this as base class if\n *\n *    a) you use the Config/Definition component for configuration,\n *    b) your configuration class is named \"Configuration\", and\n *    c) the configuration class resides in the DependencyInjection sub-folder.\n *\n * @author Johannes M. Schmitt <schmittjoh@gmail.com>\n */\nabstract class ConfigurableExtension extends Extension\n{\n    final public function load(array $configs, ContainerBuilder $container): void\n    {\n        $this->loadInternal($this->processConfiguration($this->getConfiguration($configs, $container), $configs), $container);\n    }\n\n    /**\n     * Configures the passed container according to the merged configuration.\n     */\n    abstract protected function loadInternal(array $mergedConfig, ContainerBuilder $container): void;\n}\n"
  },
  {
    "path": "DependencyInjection/ControllerArgumentValueResolverPass.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\Argument\\IteratorArgument;\nuse Symfony\\Component\\DependencyInjection\\Argument\\ServiceLocatorArgument;\nuse Symfony\\Component\\DependencyInjection\\Argument\\TaggedIteratorArgument;\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\Compiler\\PriorityTaggedServiceTrait;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\TraceableValueResolver;\nuse Symfony\\Component\\Stopwatch\\Stopwatch;\n\n/**\n * Gathers and configures the argument value resolvers.\n *\n * @author Iltar van der Berg <kjarli@gmail.com>\n */\nclass ControllerArgumentValueResolverPass implements CompilerPassInterface\n{\n    use PriorityTaggedServiceTrait;\n\n    public function process(ContainerBuilder $container): void\n    {\n        if (!$container->hasDefinition('argument_resolver')) {\n            return;\n        }\n\n        $definitions = $container->getDefinitions();\n        $namedResolvers = $this->findAndSortTaggedServices(new TaggedIteratorArgument('controller.targeted_value_resolver', 'name', needsIndexes: true), $container);\n        $resolvers = $this->findAndSortTaggedServices(new TaggedIteratorArgument('controller.argument_value_resolver', 'name', needsIndexes: true), $container);\n\n        foreach ($resolvers as $name => $resolver) {\n            if ($definitions[(string) $resolver]->hasTag('controller.targeted_value_resolver')) {\n                unset($resolvers[$name]);\n            } else {\n                $namedResolvers[$name] ??= clone $resolver;\n            }\n        }\n\n        if ($container->getParameter('kernel.debug') && class_exists(Stopwatch::class) && $container->has('debug.stopwatch')) {\n            foreach ($resolvers as $name => $resolver) {\n                $resolvers[$name] = new Reference('.debug.value_resolver.'.$resolver);\n                $container->register('.debug.value_resolver.'.$resolver, TraceableValueResolver::class)\n                    ->setArguments([$resolver, new Reference('debug.stopwatch')]);\n            }\n            foreach ($namedResolvers as $name => $resolver) {\n                $namedResolvers[$name] = new Reference('.debug.value_resolver.'.$resolver);\n                $container->register('.debug.value_resolver.'.$resolver, TraceableValueResolver::class)\n                    ->setArguments([$resolver, new Reference('debug.stopwatch')]);\n            }\n        }\n\n        $container\n            ->getDefinition('argument_resolver')\n            ->replaceArgument(1, new IteratorArgument(array_values($resolvers)))\n            ->setArgument(2, new ServiceLocatorArgument($namedResolvers))\n        ;\n    }\n}\n"
  },
  {
    "path": "DependencyInjection/ControllerAttributesListenerPass.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\n\n/**\n * Collects attribute listeners and registers them for ControllerAttributesListener.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass ControllerAttributesListenerPass implements CompilerPassInterface\n{\n    private const ATTRIBUTE_EVENTS = [\n        KernelEvents::CONTROLLER,\n        KernelEvents::CONTROLLER_ARGUMENTS,\n        KernelEvents::VIEW,\n        KernelEvents::RESPONSE,\n        KernelEvents::EXCEPTION,\n        KernelEvents::FINISH_REQUEST,\n    ];\n\n    public function process(ContainerBuilder $container): void\n    {\n        if (!$container->has('event_dispatcher') || !$container->hasDefinition('kernel.controller_attributes_listener')) {\n            return;\n        }\n\n        $dispatcherDefinition = $container->findDefinition('event_dispatcher');\n        $attributesWithListeners = [];\n\n        foreach ($dispatcherDefinition->getMethodCalls() as [$method, $arguments]) {\n            if ('addListener' !== $method || !\\is_string($eventName = $arguments[0] ?? null)) {\n                continue;\n            }\n\n            foreach (self::ATTRIBUTE_EVENTS as $kernelEvent) {\n                if ('.' === ($eventName[\\strlen($kernelEvent)] ?? null) && str_starts_with($eventName, $kernelEvent)) {\n                    $attributesWithListeners[$kernelEvent][substr($eventName, \\strlen($kernelEvent) + 1)] = true;\n                    break;\n                }\n            }\n        }\n\n        $container->getDefinition('kernel.controller_attributes_listener')->replaceArgument(0, $attributesWithListeners);\n    }\n}\n"
  },
  {
    "path": "DependencyInjection/Extension.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\Extension\\Extension as BaseExtension;\n\ntrigger_deprecation('symfony/http-kernel', '8.1', 'The \"%s\" class is deprecated, use \"%s\" instead.', Extension::class, BaseExtension::class);\n\n/**\n * Allow adding classes to the class cache.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @deprecated since Symfony 8.1; use Symfony\\Component\\DependencyInjection\\Extension\\Extension instead\n */\nabstract class Extension extends BaseExtension\n{\n}\n"
  },
  {
    "path": "DependencyInjection/FragmentRendererPass.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\Compiler\\ServiceLocatorTagPass;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\HttpKernel\\Fragment\\FragmentRendererInterface;\n\n/**\n * Adds services tagged kernel.fragment_renderer as HTTP content rendering strategies.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass FragmentRendererPass implements CompilerPassInterface\n{\n    public function process(ContainerBuilder $container): void\n    {\n        if (!$container->hasDefinition('fragment.handler')) {\n            return;\n        }\n\n        $definition = $container->getDefinition('fragment.handler');\n        $renderers = [];\n        foreach ($container->findTaggedServiceIds('kernel.fragment_renderer', true) as $id => $tags) {\n            $def = $container->getDefinition($id);\n            $class = $container->getParameterBag()->resolveValue($def->getClass());\n\n            if (!$r = $container->getReflectionClass($class)) {\n                throw new InvalidArgumentException(\\sprintf('Class \"%s\" used for service \"%s\" cannot be found.', $class, $id));\n            }\n            if (!$r->isSubclassOf(FragmentRendererInterface::class)) {\n                throw new InvalidArgumentException(\\sprintf('Service \"%s\" must implement interface \"%s\".', $id, FragmentRendererInterface::class));\n            }\n\n            foreach ($tags as $tag) {\n                $renderers[$tag['alias']] = new Reference($id);\n            }\n        }\n\n        $definition->replaceArgument(0, ServiceLocatorTagPass::register($container, $renderers));\n    }\n}\n"
  },
  {
    "path": "DependencyInjection/LazyLoadingFragmentHandler.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DependencyInjection;\n\nuse Psr\\Container\\ContainerInterface;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerReference;\nuse Symfony\\Component\\HttpKernel\\Fragment\\FragmentHandler;\n\n/**\n * Lazily loads fragment renderers from the dependency injection container.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass LazyLoadingFragmentHandler extends FragmentHandler\n{\n    /**\n     * @var array<string, bool>\n     */\n    private array $initialized = [];\n\n    public function __construct(\n        private ContainerInterface $container,\n        RequestStack $requestStack,\n        bool $debug = false,\n    ) {\n        parent::__construct($requestStack, [], $debug);\n    }\n\n    public function render(string|ControllerReference $uri, string $renderer = 'inline', array $options = []): ?string\n    {\n        if (!isset($this->initialized[$renderer]) && $this->container->has($renderer)) {\n            $this->addRenderer($this->container->get($renderer));\n            $this->initialized[$renderer] = true;\n        }\n\n        return parent::render($uri, $renderer, $options);\n    }\n}\n"
  },
  {
    "path": "DependencyInjection/LoggerPass.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DependencyInjection;\n\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpKernel\\Log\\Logger;\n\n/**\n * Registers the default logger if necessary.\n *\n * @author Kévin Dunglas <dunglas@gmail.com>\n */\nclass LoggerPass implements CompilerPassInterface\n{\n    public function process(ContainerBuilder $container): void\n    {\n        if (!$container->has(LoggerInterface::class)) {\n            $container->setAlias(LoggerInterface::class, 'logger');\n        }\n\n        if ($container->has('logger')) {\n            return;\n        }\n\n        if ($debug = $container->getParameter('kernel.debug')) {\n            $debug = $container->hasParameter('kernel.runtime_mode.web')\n                ? $container->getParameter('kernel.runtime_mode.web')\n                : !\\in_array(\\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true);\n        }\n\n        $container->register('logger', Logger::class)\n            ->setArguments([null, null, null, new Reference(RequestStack::class), $debug]);\n    }\n}\n"
  },
  {
    "path": "DependencyInjection/MergeExtensionConfigurationPass.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\Compiler\\MergeExtensionConfigurationPass as BaseMergeExtensionConfigurationPass;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\n\n/**\n * Ensures certain extensions are always loaded.\n *\n * @author Kris Wallsmith <kris@symfony.com>\n */\nclass MergeExtensionConfigurationPass extends BaseMergeExtensionConfigurationPass\n{\n    /**\n     * @param string[] $extensions\n     */\n    public function __construct(\n        private array $extensions,\n    ) {\n    }\n\n    public function process(ContainerBuilder $container): void\n    {\n        foreach ($this->extensions as $extension) {\n            if (!\\count($container->getExtensionConfig($extension))) {\n                $container->loadFromExtension($extension, []);\n            }\n        }\n\n        parent::process($container);\n    }\n}\n"
  },
  {
    "path": "DependencyInjection/RegisterControllerArgumentLocatorsPass.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\Attribute\\Autowire;\nuse Symfony\\Component\\DependencyInjection\\Attribute\\AutowireCallable;\nuse Symfony\\Component\\DependencyInjection\\Attribute\\Target;\nuse Symfony\\Component\\DependencyInjection\\ChildDefinition;\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\Compiler\\ServiceLocatorTagPass;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\ContainerInterface;\nuse Symfony\\Component\\DependencyInjection\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\DependencyInjection\\TypedReference;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpFoundation\\Session\\SessionInterface;\nuse Symfony\\Component\\VarExporter\\ProxyHelper;\n\n/**\n * Creates the service-locators required by ServiceValueResolver.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass RegisterControllerArgumentLocatorsPass implements CompilerPassInterface\n{\n    public function process(ContainerBuilder $container): void\n    {\n        if (!$container->hasDefinition('argument_resolver.service') && !$container->hasDefinition('argument_resolver.not_tagged_controller')) {\n            return;\n        }\n\n        $parameterBag = $container->getParameterBag();\n        $controllers = [];\n        $controllerClasses = [];\n\n        $publicAliases = [];\n        foreach ($container->getAliases() as $id => $alias) {\n            if ($alias->isPublic()) {\n                $publicAliases[(string) $alias][] = $id;\n            }\n        }\n\n        foreach ($container->findTaggedServiceIds('controller.service_arguments', true) as $id => $tags) {\n            $def = $container->getDefinition($id);\n            $def->setPublic(true);\n            $def->setLazy(false);\n            $class = $def->getClass();\n            $autowire = $def->isAutowired();\n            $bindings = $def->getBindings();\n\n            // resolve service class, taking parent definitions into account\n            while ($def instanceof ChildDefinition) {\n                $def = $container->findDefinition($def->getParent());\n                $class = $class ?: $def->getClass();\n                $bindings += $def->getBindings();\n            }\n            $class = $parameterBag->resolveValue($class);\n\n            if (!$r = $container->getReflectionClass($class)) {\n                throw new InvalidArgumentException(\\sprintf('Class \"%s\" used for service \"%s\" cannot be found.', $class, $id));\n            }\n\n            $controllerClasses[] = $class;\n\n            // get regular public methods\n            $methods = [];\n            $arguments = [];\n            foreach ($r->getMethods(\\ReflectionMethod::IS_PUBLIC) as $r) {\n                if ('setContainer' === $r->name) {\n                    continue;\n                }\n                if (!$r->isConstructor() && !$r->isDestructor() && !$r->isAbstract()) {\n                    $methods[strtolower($r->name)] = [$r, $r->getParameters()];\n                }\n            }\n\n            // validate and collect explicit per-actions and per-arguments service references\n            foreach ($tags as $attributes) {\n                if (!isset($attributes['action']) && !isset($attributes['argument']) && !isset($attributes['id'])) {\n                    $autowire = true;\n                    continue;\n                }\n                foreach (['action', 'argument', 'id'] as $k) {\n                    if (!isset($attributes[$k][0])) {\n                        throw new InvalidArgumentException(\\sprintf('Missing \"%s\" attribute on tag \"controller.service_arguments\" %s for service \"%s\".', $k, json_encode($attributes, \\JSON_UNESCAPED_UNICODE), $id));\n                    }\n                }\n                if (!isset($methods[$action = strtolower($attributes['action'])])) {\n                    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));\n                }\n                [$r, $parameters] = $methods[$action];\n                $found = false;\n\n                foreach ($parameters as $p) {\n                    if ($attributes['argument'] === $p->name) {\n                        if (!isset($arguments[$r->name][$p->name])) {\n                            $arguments[$r->name][$p->name] = $attributes['id'];\n                        }\n                        $found = true;\n                        break;\n                    }\n                }\n\n                if (!$found) {\n                    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));\n                }\n            }\n\n            foreach ($methods as [$r, $parameters]) {\n                /** @var \\ReflectionMethod $r */\n\n                // create a per-method map of argument-names to service/type-references\n                $args = [];\n                $erroredIds = 0;\n                foreach ($parameters as $p) {\n                    /** @var \\ReflectionParameter $p */\n                    $type = preg_replace('/(^|[(|&])\\\\\\\\/', '\\1', $target = ltrim(ProxyHelper::exportType($p) ?? '', '?'));\n                    $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;\n                    $autowireAttributes = null;\n                    $parsedName = $p->name;\n                    $k = null;\n\n                    if (isset($arguments[$r->name][$p->name])) {\n                        $target = $arguments[$r->name][$p->name];\n                        if ('?' !== $target[0]) {\n                            $invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE;\n                        } elseif ('' === $target = substr($target, 1)) {\n                            throw new InvalidArgumentException(\\sprintf('A \"controller.service_arguments\" tag must have non-empty \"id\" attributes for service \"%s\".', $id));\n                        } elseif ($p->allowsNull() && !$p->isOptional()) {\n                            $invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE;\n                        }\n                    } elseif (isset($bindings[$bindingName = $type.' $'.$name = Target::parseName($p, $k, $parsedName)])\n                        || isset($bindings[$bindingName = $type.' $'.$parsedName])\n                        || isset($bindings[$bindingName = '$'.$name])\n                        || isset($bindings[$bindingName = $type])\n                    ) {\n                        $binding = $bindings[$bindingName];\n\n                        [$bindingValue, $bindingId, , $bindingType, $bindingFile] = $binding->getValues();\n                        $binding->setValues([$bindingValue, $bindingId, true, $bindingType, $bindingFile]);\n\n                        $args[$p->name] = $bindingValue;\n\n                        continue;\n                    } elseif (!$autowire || (!($autowireAttributes = $p->getAttributes(Autowire::class, \\ReflectionAttribute::IS_INSTANCEOF)) && (!$type || '\\\\' !== $target[0]))) {\n                        continue;\n                    } elseif (!$autowireAttributes && is_subclass_of($type, \\UnitEnum::class)) {\n                        // do not attempt to register enum typed arguments if not already present in bindings\n                        continue;\n                    } elseif (!$p->allowsNull()) {\n                        $invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE;\n                    }\n\n                    if (Request::class === $type || SessionInterface::class === $type || Response::class === $type) {\n                        continue;\n                    }\n\n                    if ($autowireAttributes) {\n                        $attribute = $autowireAttributes[0]->newInstance();\n                        $value = $parameterBag->resolveValue($attribute->value);\n\n                        if ($attribute instanceof AutowireCallable) {\n                            $args[$p->name] = $attribute->buildDefinition($value, $type, $p);\n                        } elseif ($value instanceof Reference) {\n                            $args[$p->name] = $type ? new TypedReference($value, $type, $invalidBehavior, $p->name) : new Reference($value, $invalidBehavior);\n                        } else {\n                            $args[$p->name] = new Reference('.value.'.$container->hash($value));\n                            $container->register((string) $args[$p->name], 'mixed')\n                                ->setFactory('current')\n                                ->addArgument([$value]);\n                        }\n\n                        continue;\n                    }\n\n                    if ($type && !$p->isOptional() && !$p->allowsNull() && !class_exists($type) && !interface_exists($type, false)) {\n                        $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);\n\n                        // see if the type-hint lives in the same namespace as the controller\n                        if (0 === strncmp($type, $class, strrpos($class, '\\\\'))) {\n                            $message .= ' Did you forget to add a use statement?';\n                        }\n\n                        $container->register($erroredId = '.errored.'.$container->hash($message), $type)\n                            ->addError($message);\n\n                        $args[$p->name] = new Reference($erroredId, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE);\n                        ++$erroredIds;\n                    } else {\n                        $targetAttribute = null;\n                        $name = Target::parseName($p, $targetAttribute);\n                        $target = preg_replace('/(^|[(|&])\\\\\\\\/', '\\\\1', $target);\n                        $args[$p->name] = $type ? new TypedReference($target, $type, $invalidBehavior, $name, $targetAttribute ? [$targetAttribute] : []) : new Reference($target, $invalidBehavior);\n                    }\n                }\n                // register the maps as a per-method service-locators\n                if ($args) {\n                    $controllers[$id.'::'.$r->name] = ServiceLocatorTagPass::register($container, $args, \\count($args) !== $erroredIds ? $id.'::'.$r->name.'()' : null);\n\n                    foreach ($publicAliases[$id] ?? [] as $alias) {\n                        $controllers[$alias.'::'.$r->name] = clone $controllers[$id.'::'.$r->name];\n                    }\n                }\n            }\n        }\n\n        $controllerLocatorRef = ServiceLocatorTagPass::register($container, $controllers);\n\n        if ($container->hasDefinition('argument_resolver.service')) {\n            $container->getDefinition('argument_resolver.service')\n                ->replaceArgument(0, $controllerLocatorRef);\n        }\n\n        if ($container->hasDefinition('argument_resolver.not_tagged_controller')) {\n            $container->getDefinition('argument_resolver.not_tagged_controller')\n                ->replaceArgument(0, $controllerLocatorRef);\n        }\n\n        $container->setAlias('argument_resolver.controller_locator', (string) $controllerLocatorRef);\n\n        if ($container->hasDefinition('controller_resolver')) {\n            $container->getDefinition('controller_resolver')\n                ->addMethodCall('allowControllers', [array_unique($controllerClasses)]);\n        }\n    }\n}\n"
  },
  {
    "path": "DependencyInjection/RegisterLocaleAwareServicesPass.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\Argument\\IteratorArgument;\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Reference;\n\n/**\n * Register all services that have the \"kernel.locale_aware\" tag into the listener.\n *\n * @author Pierre Bobiet <pierrebobiet@gmail.com>\n */\nclass RegisterLocaleAwareServicesPass implements CompilerPassInterface\n{\n    public function process(ContainerBuilder $container): void\n    {\n        if (!$container->hasDefinition('locale_aware_listener')) {\n            return;\n        }\n\n        $services = [];\n\n        foreach ($container->findTaggedServiceIds('kernel.locale_aware') as $id => $tags) {\n            $services[] = new Reference($id);\n        }\n\n        if (!$services) {\n            $container->removeDefinition('locale_aware_listener');\n\n            return;\n        }\n\n        $container\n            ->getDefinition('locale_aware_listener')\n            ->setArgument(0, new IteratorArgument($services))\n        ;\n    }\n}\n"
  },
  {
    "path": "DependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\n\n/**\n * Removes empty service-locators registered for ServiceValueResolver.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass RemoveEmptyControllerArgumentLocatorsPass implements CompilerPassInterface\n{\n    public function process(ContainerBuilder $container): void\n    {\n        $controllerLocator = $container->findDefinition('argument_resolver.controller_locator');\n        $controllers = $controllerLocator->getArgument(0);\n\n        foreach ($controllers as $controller => $argumentRef) {\n            $argumentLocator = $container->getDefinition((string) $argumentRef->getValues()[0]);\n\n            if ($argumentLocator->getFactory()) {\n                $argumentLocator = $container->getDefinition($argumentLocator->getFactory()[0]);\n            }\n\n            if (!$argumentLocator->getArgument(0)) {\n                // remove empty argument locators\n                $reason = \\sprintf('Removing service-argument resolver for controller \"%s\": no corresponding services exist for the referenced types.', $controller);\n            } else {\n                // any methods listed for call-at-instantiation cannot be actions\n                $reason = false;\n                [$id, $action] = explode('::', $controller);\n\n                if ($container->hasAlias($id)) {\n                    continue;\n                }\n\n                $controllerDef = $container->getDefinition($id);\n                foreach ($controllerDef->getMethodCalls() as [$method]) {\n                    if (0 === strcasecmp($action, $method)) {\n                        $reason = \\sprintf('Removing method \"%s\" of service \"%s\" from controller candidates: the method is called at instantiation, thus cannot be an action.', $action, $id);\n                        break;\n                    }\n                }\n                if (!$reason) {\n                    // see Symfony\\Component\\HttpKernel\\Controller\\ContainerControllerResolver\n                    $controllers[$id.':'.$action] = $argumentRef;\n\n                    if ('__invoke' === $action) {\n                        $controllers[$id] = $argumentRef;\n                    }\n                    continue;\n                }\n            }\n\n            unset($controllers[$controller]);\n            $container->log($this, $reason);\n        }\n\n        $controllerLocator->replaceArgument(0, $controllers);\n    }\n}\n"
  },
  {
    "path": "DependencyInjection/ResettableServicePass.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\Argument\\IteratorArgument;\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\ContainerInterface;\nuse Symfony\\Component\\DependencyInjection\\Exception\\RuntimeException;\nuse Symfony\\Component\\DependencyInjection\\Reference;\n\n/**\n * @author Alexander M. Turek <me@derrabus.de>\n */\nclass ResettableServicePass implements CompilerPassInterface\n{\n    public function process(ContainerBuilder $container): void\n    {\n        if (!$container->has('services_resetter')) {\n            return;\n        }\n\n        $services = $methods = [];\n\n        foreach ($container->findTaggedServiceIds('kernel.reset', true) as $id => $tags) {\n            $services[$id] = new Reference($id, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE);\n\n            foreach ($tags as $attributes) {\n                if (!isset($attributes['method'])) {\n                    throw new RuntimeException(\\sprintf('Tag \"kernel.reset\" requires the \"method\" attribute to be set on service \"%s\".', $id));\n                }\n\n                if (!isset($methods[$id])) {\n                    $methods[$id] = [];\n                }\n\n                if ('ignore' === ($attributes['on_invalid'] ?? null)) {\n                    $attributes['method'] = '?'.$attributes['method'];\n                }\n\n                $methods[$id][] = $attributes['method'];\n            }\n        }\n\n        if (!$services) {\n            $container->removeAlias('services_resetter');\n            $container->removeDefinition('services_resetter');\n\n            return;\n        }\n\n        $container->findDefinition('services_resetter')\n            ->setArgument(0, new IteratorArgument($services))\n            ->setArgument(1, $methods);\n    }\n}\n"
  },
  {
    "path": "DependencyInjection/ServicesResetter.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DependencyInjection;\n\nuse ProxyManager\\Proxy\\LazyLoadingInterface;\nuse Symfony\\Component\\VarExporter\\LazyObjectInterface;\n\n/**\n * Resets provided services.\n *\n * @author Alexander M. Turek <me@derrabus.de>\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class ServicesResetter implements ServicesResetterInterface\n{\n    /**\n     * @param \\Traversable<string, object>   $resettableServices\n     * @param array<string, string|string[]> $resetMethods\n     */\n    public function __construct(\n        private \\Traversable $resettableServices,\n        private array $resetMethods,\n    ) {\n    }\n\n    public function reset(): void\n    {\n        foreach ($this->resettableServices as $id => $service) {\n            if ($service instanceof LazyObjectInterface && !$service->isLazyObjectInitialized(true)) {\n                continue;\n            }\n\n            if ($service instanceof LazyLoadingInterface && !$service->isProxyInitialized()) {\n                continue;\n            }\n\n            if (new \\ReflectionClass($service)->isUninitializedLazyObject($service)) {\n                continue;\n            }\n\n            foreach ((array) $this->resetMethods[$id] as $resetMethod) {\n                if ('?' === $resetMethod[0] && !method_exists($service, $resetMethod = substr($resetMethod, 1))) {\n                    continue;\n                }\n\n                $service->$resetMethod();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "DependencyInjection/ServicesResetterInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\DependencyInjection;\n\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * Resets provided services.\n */\ninterface ServicesResetterInterface extends ResetInterface\n{\n}\n"
  },
  {
    "path": "Event/ControllerArgumentsEvent.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Event;\n\nuse Symfony\\Component\\ExpressionLanguage\\Expression;\nuse Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\n\n/**\n * Allows filtering of controller arguments.\n *\n * You can call getController() to retrieve the controller and getArguments\n * to retrieve the current arguments. With setArguments() you can replace\n * arguments that are used to call the controller.\n *\n * Arguments set in the event must be compatible with the signature of the\n * controller.\n *\n * @author Christophe Coevoet <stof@notk.org>\n */\nfinal class ControllerArgumentsEvent extends KernelEvent\n{\n    private ControllerEvent $controllerEvent;\n    private array $namedArguments;\n\n    public function __construct(\n        HttpKernelInterface $kernel,\n        callable|ControllerEvent $controller,\n        private array $arguments,\n        Request $request,\n        ?int $requestType,\n    ) {\n        parent::__construct($kernel, $request, $requestType);\n\n        if (!$controller instanceof ControllerEvent) {\n            $controller = new ControllerEvent($kernel, $controller, $request, $requestType);\n        }\n\n        $this->controllerEvent = $controller;\n    }\n\n    public function getController(): callable\n    {\n        return $this->controllerEvent->getController();\n    }\n\n    /**\n     * @param list<object>|null $attributes\n     */\n    public function setController(callable $controller, ?array $attributes = null): void\n    {\n        $this->controllerEvent->setController($controller, $attributes);\n        unset($this->namedArguments);\n    }\n\n    /**\n     * @return list<mixed>\n     */\n    public function getArguments(): array\n    {\n        return $this->arguments;\n    }\n\n    /**\n     * @param list<mixed> $arguments\n     */\n    public function setArguments(array $arguments): void\n    {\n        $this->arguments = $arguments;\n        unset($this->namedArguments);\n    }\n\n    /**\n     * @return array<string, mixed>\n     */\n    public function getNamedArguments(): array\n    {\n        if (isset($this->namedArguments)) {\n            return $this->namedArguments;\n        }\n\n        $namedArguments = [];\n        $arguments = $this->arguments;\n\n        foreach ($this->controllerEvent->getControllerReflector()->getParameters() as $i => $param) {\n            if ($param->isVariadic()) {\n                $namedArguments[$param->name] = \\array_slice($arguments, $i);\n                break;\n            }\n            if (\\array_key_exists($i, $arguments)) {\n                $namedArguments[$param->name] = $arguments[$i];\n            } elseif ($param->isDefaultvalueAvailable()) {\n                $namedArguments[$param->name] = $param->getDefaultValue();\n            }\n        }\n\n        return $this->namedArguments = $namedArguments;\n    }\n\n    /**\n     * @template T of object\n     *\n     * @param class-string<T>|'*'|null $className\n     *\n     * @return ($className is null ? array<class-string, list<object>> : ($className is '*' ? list<object> : list<T>))\n     */\n    public function getAttributes(?string $className = null): array\n    {\n        return $this->controllerEvent->getAttributes($className);\n    }\n\n    public function evaluate(mixed $value, ?ExpressionLanguage $expressionLanguage): mixed\n    {\n        if (!$value instanceof \\Closure && !$value instanceof Expression) {\n            return $value;\n        }\n\n        return $this->controllerEvent->evaluate($value, $expressionLanguage, $this->getNamedArguments());\n    }\n}\n"
  },
  {
    "path": "Event/ControllerArgumentsMetadata.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Event;\n\nuse Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage;\n\n/**\n * Provides read-only access to controller metadata.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass ControllerArgumentsMetadata extends ControllerMetadata\n{\n    public function __construct(\n        ControllerEvent $controllerEvent,\n        private ControllerArgumentsEvent $controllerArgumentsEvent,\n    ) {\n        parent::__construct($controllerEvent);\n    }\n\n    /**\n     * @return list<mixed>\n     */\n    public function getArguments(): array\n    {\n        return $this->controllerArgumentsEvent->getArguments();\n    }\n\n    /**\n     * @return array<string, mixed>\n     */\n    public function getNamedArguments(): array\n    {\n        return $this->controllerArgumentsEvent->getNamedArguments();\n    }\n\n    public function evaluate(mixed $value, ?ExpressionLanguage $expressionLanguage): mixed\n    {\n        return $this->controllerArgumentsEvent->evaluate($value, $expressionLanguage);\n    }\n}\n"
  },
  {
    "path": "Event/ControllerAttributeEvent.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Event;\n\nuse Psr\\EventDispatcher\\StoppableEventInterface;\nuse Symfony\\Component\\ExpressionLanguage\\Expression;\nuse Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage;\n\n/**\n * Event dispatched for each controller attribute.\n *\n * @template T of object\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class ControllerAttributeEvent implements StoppableEventInterface\n{\n    private string|array|object|null $controller;\n\n    /**\n     * @param T $attribute\n     */\n    public function __construct(\n        /** @var T */\n        public readonly object $attribute,\n        public readonly KernelEvent $kernelEvent,\n        private readonly ?ExpressionLanguage $expressionLanguage = null,\n    ) {\n        $this->controller = match (true) {\n            $kernelEvent instanceof ControllerEvent => $kernelEvent->getController(),\n            $kernelEvent instanceof ControllerArgumentsEvent => $kernelEvent->getController(),\n            default => null,\n        };\n    }\n\n    public function isPropagationStopped(): bool\n    {\n        $event = $this->kernelEvent;\n\n        if ($event->isPropagationStopped()) {\n            return true;\n        }\n\n        if (!$this->controller) {\n            return false;\n        }\n\n        $controller = match (true) {\n            $event instanceof ControllerEvent => $event->getController(),\n            $event instanceof ControllerArgumentsEvent => $event->getController(),\n        };\n\n        return $controller instanceof \\Closure ? $controller != $this->controller : $controller !== $this->controller;\n    }\n\n    public function evaluate(mixed $value, ?ExpressionLanguage $expressionLanguage = null): mixed\n    {\n        if (!$value instanceof \\Closure && !$value instanceof Expression) {\n            return $value;\n        }\n\n        $event = $this->kernelEvent;\n        $expressionLanguage ??= $this->expressionLanguage;\n\n        return match (true) {\n            $event instanceof ControllerEvent => $event->evaluate($value, $expressionLanguage),\n            $event instanceof ControllerArgumentsEvent => $event->evaluate($value, $expressionLanguage),\n            ($m = $event->controllerMetadata ?? null) instanceof ControllerMetadata => $m->evaluate($value, $expressionLanguage),\n        };\n    }\n}\n"
  },
  {
    "path": "Event/ControllerEvent.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Event;\n\nuse Symfony\\Component\\ExpressionLanguage\\Expression;\nuse Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\n\n/**\n * Allows filtering of a controller callable.\n *\n * You can call getController() to retrieve the current controller. With\n * setController() you can set a new controller that is used in the processing\n * of the request.\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nfinal class ControllerEvent extends KernelEvent\n{\n    private string|array|object $controller;\n    private \\ReflectionFunctionAbstract $controllerReflector;\n\n    public function __construct(HttpKernelInterface $kernel, callable $controller, Request $request, ?int $requestType)\n    {\n        parent::__construct($kernel, $request, $requestType);\n\n        $this->setController($controller);\n    }\n\n    public function getController(): callable\n    {\n        return $this->controller;\n    }\n\n    public function getControllerReflector(): \\ReflectionFunctionAbstract\n    {\n        return $this->controllerReflector;\n    }\n\n    /**\n     * @param list<object>|null $attributes\n     */\n    public function setController(callable $controller, ?array $attributes = null): void\n    {\n        if (null !== $attributes) {\n            if (!array_is_list($flattenAttributes = $attributes)) {\n                trigger_deprecation('symfony/http-kernel', '8.1', 'Passing an array of attributes grouped by class name to \"%s()\" is deprecated. Pass a flat list of attributes instead.', __METHOD__);\n                $flattenAttributes = [];\n                foreach ($attributes as $attributes) {\n                    foreach (\\is_array($attributes) ? $attributes : [$attributes] as $attribute) {\n                        $flattenAttributes[] = $attribute;\n                    }\n                }\n            }\n            $this->getRequest()->attributes->set('_controller_attributes', $flattenAttributes);\n        }\n\n        if (isset($this->controller) && ($controller instanceof \\Closure ? $controller == $this->controller : $controller === $this->controller)) {\n            $this->controller = $controller;\n\n            return;\n        }\n\n        if (null === $attributes) {\n            $this->getRequest()->attributes->remove('_controller_attributes');\n        }\n\n        $this->controllerReflector = match (true) {\n            \\is_array($controller) && method_exists(...$controller) => new \\ReflectionMethod(...$controller),\n            \\is_string($controller) && str_contains($controller, '::') => new \\ReflectionMethod(...explode('::', $controller, 2)),\n            default => new \\ReflectionFunction($controller(...)),\n        };\n\n        $this->controller = $controller;\n    }\n\n    /**\n     * @template T of object\n     *\n     * @param class-string<T>|'*'|null $className\n     *\n     * @return ($className is null ? array<class-string, list<object>> : ($className is '*' ? list<object> : list<T>))\n     */\n    public function getAttributes(?string $className = null): array\n    {\n        if (null === $attributes = $this->getRequest()->attributes->get('_controller_attributes')) {\n            $class = match (true) {\n                \\is_array($this->controller) && method_exists(...$this->controller) => new \\ReflectionClass($this->controller[0]),\n                \\is_string($this->controller) && false !== $i = strpos($this->controller, '::') => new \\ReflectionClass(substr($this->controller, 0, $i)),\n                $this->controllerReflector instanceof \\ReflectionFunction => $this->controllerReflector->isAnonymous() ? null : $this->controllerReflector->getClosureCalledClass(),\n            };\n            $attributes = [];\n\n            foreach (array_merge($class?->getAttributes() ?? [], $this->controllerReflector->getAttributes()) as $attribute) {\n                if (class_exists($attribute->getName())) {\n                    $attributes[] = $attribute->newInstance();\n                }\n            }\n\n            $this->getRequest()->attributes->set('_controller_attributes', $attributes);\n        }\n\n        if ('*' === $className) {\n            return $attributes;\n        }\n\n        if (null !== $className) {\n            return array_values(array_filter($attributes, static fn ($attr) => $attr instanceof $className));\n        }\n\n        $grouped = [];\n        foreach ($attributes as $attribute) {\n            $grouped[$attribute::class][] = $attribute;\n        }\n\n        return $grouped;\n    }\n\n    public function evaluate(mixed $value, ?ExpressionLanguage $expressionLanguage, array $args = []): mixed\n    {\n        if (!$value instanceof \\Closure && !$value instanceof Expression) {\n            return $value;\n        }\n\n        $controller = $this->getController();\n        $controller = match (true) {\n            \\is_object($controller) && !$controller instanceof \\Closure => $controller,\n            \\is_array($controller) && \\is_object($controller[0]) => $controller[0],\n            default => null,\n        };\n\n        if ($value instanceof \\Closure) {\n            return $value($args, $this->getRequest(), $controller);\n        }\n\n        if (!$expressionLanguage) {\n            throw new \\LogicException('Cannot evaluate Expression for controllers since no ExpressionLanguage service was configured.');\n        }\n\n        return $expressionLanguage->evaluate($value, [\n            'request' => $this->getRequest(),\n            'args' => $args,\n            'this' => $controller,\n        ]);\n    }\n}\n"
  },
  {
    "path": "Event/ControllerMetadata.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Event;\n\nuse Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage;\n\n/**\n * Provides read-only access to controller metadata.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass ControllerMetadata\n{\n    public function __construct(\n        private ControllerEvent $controllerEvent,\n    ) {\n    }\n\n    public function getController(): callable\n    {\n        return $this->controllerEvent->getController();\n    }\n\n    public function getReflector(): \\ReflectionFunctionAbstract\n    {\n        return $this->controllerEvent->getControllerReflector();\n    }\n\n    /**\n     * @template T of object\n     *\n     * @param class-string<T>|'*'|null $className\n     *\n     * @return ($className is null ? array<class-string, list<object>> : ($className is '*' ? list<object> : list<T>))\n     */\n    public function getAttributes(?string $className = null): array\n    {\n        return $this->controllerEvent->getAttributes($className);\n    }\n\n    public function evaluate(mixed $value, ?ExpressionLanguage $expressionLanguage): mixed\n    {\n        return $this->controllerEvent->evaluate($value, $expressionLanguage);\n    }\n}\n"
  },
  {
    "path": "Event/ExceptionEvent.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Event;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\n\n/**\n * Allows to create a response for a thrown exception.\n *\n * Call setResponse() to set the response that will be returned for the\n * current request. The propagation of this event is stopped as soon as a\n * response is set.\n *\n * You can also call setThrowable() to replace the thrown exception. This\n * exception will be thrown if no response is set during processing of this\n * event.\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nfinal class ExceptionEvent extends RequestEvent\n{\n    private \\Throwable $throwable;\n    private bool $allowCustomResponseCode = false;\n\n    public function __construct(\n        HttpKernelInterface $kernel,\n        Request $request,\n        int $requestType,\n        \\Throwable $e,\n        private bool $isKernelTerminating = false,\n        public readonly ?ControllerMetadata $controllerMetadata = null,\n    ) {\n        parent::__construct($kernel, $request, $requestType);\n\n        $this->setThrowable($e);\n    }\n\n    public function getThrowable(): \\Throwable\n    {\n        return $this->throwable;\n    }\n\n    /**\n     * Replaces the thrown exception.\n     *\n     * This exception will be thrown if no response is set in the event.\n     */\n    public function setThrowable(\\Throwable $exception): void\n    {\n        $this->throwable = $exception;\n    }\n\n    /**\n     * Mark the event as allowing a custom response code.\n     */\n    public function allowCustomResponseCode(): void\n    {\n        $this->allowCustomResponseCode = true;\n    }\n\n    /**\n     * Returns true if the event allows a custom response code.\n     */\n    public function isAllowingCustomResponseCode(): bool\n    {\n        return $this->allowCustomResponseCode;\n    }\n\n    public function isKernelTerminating(): bool\n    {\n        return $this->isKernelTerminating;\n    }\n}\n"
  },
  {
    "path": "Event/FinishRequestEvent.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Event;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\n\n/**\n * Triggered whenever a request is fully processed.\n *\n * @author Benjamin Eberlei <kontakt@beberlei.de>\n */\nfinal class FinishRequestEvent extends KernelEvent\n{\n    public function __construct(\n        HttpKernelInterface $kernel,\n        Request $request,\n        ?int $requestType,\n        public readonly ?ControllerMetadata $controllerMetadata = null,\n    ) {\n        parent::__construct($kernel, $request, $requestType);\n    }\n}\n"
  },
  {
    "path": "Event/KernelEvent.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Event;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Contracts\\EventDispatcher\\Event;\n\n/**\n * Base class for events dispatched in the HttpKernel component.\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass KernelEvent extends Event\n{\n    /**\n     * @param int $requestType The request type the kernel is currently processing; one of\n     *                         HttpKernelInterface::MAIN_REQUEST or HttpKernelInterface::SUB_REQUEST\n     */\n    public function __construct(\n        private HttpKernelInterface $kernel,\n        private Request $request,\n        private ?int $requestType,\n    ) {\n    }\n\n    /**\n     * Returns the kernel in which this event was thrown.\n     */\n    public function getKernel(): HttpKernelInterface\n    {\n        return $this->kernel;\n    }\n\n    /**\n     * Returns the request the kernel is currently processing.\n     */\n    public function getRequest(): Request\n    {\n        return $this->request;\n    }\n\n    /**\n     * Returns the request type the kernel is currently processing.\n     *\n     * @return int One of HttpKernelInterface::MAIN_REQUEST and\n     *             HttpKernelInterface::SUB_REQUEST\n     */\n    public function getRequestType(): int\n    {\n        return $this->requestType;\n    }\n\n    /**\n     * Checks if this is the main request.\n     */\n    public function isMainRequest(): bool\n    {\n        return HttpKernelInterface::MAIN_REQUEST === $this->requestType;\n    }\n}\n"
  },
  {
    "path": "Event/RequestEvent.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Event;\n\nuse Symfony\\Component\\HttpFoundation\\Response;\n\n/**\n * Allows to create a response for a request.\n *\n * Call setResponse() to set the response that will be returned for the\n * current request. The propagation of this event is stopped as soon as a\n * response is set.\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass RequestEvent extends KernelEvent\n{\n    private ?Response $response = null;\n\n    /**\n     * Returns the response object.\n     */\n    public function getResponse(): ?Response\n    {\n        return $this->response;\n    }\n\n    /**\n     * Sets a response and stops event propagation.\n     */\n    public function setResponse(Response $response): void\n    {\n        $this->response = $response;\n\n        $this->stopPropagation();\n    }\n\n    /**\n     * Returns whether a response was set.\n     *\n     * @psalm-assert-if-true !null $this->getResponse()\n     */\n    public function hasResponse(): bool\n    {\n        return null !== $this->response;\n    }\n}\n"
  },
  {
    "path": "Event/ResponseEvent.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Event;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\n\n/**\n * Allows to filter a Response object.\n *\n * You can call getResponse() to retrieve the current response. With\n * setResponse() you can set a new response that will be returned to the\n * browser.\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nfinal class ResponseEvent extends KernelEvent\n{\n    public function __construct(\n        HttpKernelInterface $kernel,\n        Request $request,\n        int $requestType,\n        private Response $response,\n        public readonly ?ControllerArgumentsMetadata $controllerMetadata = null,\n    ) {\n        parent::__construct($kernel, $request, $requestType);\n    }\n\n    public function getResponse(): Response\n    {\n        return $this->response;\n    }\n\n    public function setResponse(Response $response): void\n    {\n        $this->response = $response;\n    }\n}\n"
  },
  {
    "path": "Event/TerminateEvent.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Event;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\n\n/**\n * Allows to execute logic after a response was sent.\n *\n * Since it's only triggered on main requests, the `getRequestType()` method\n * will always return the value of `HttpKernelInterface::MAIN_REQUEST`.\n *\n * @author Jordi Boggiano <j.boggiano@seld.be>\n */\nfinal class TerminateEvent extends KernelEvent\n{\n    public function __construct(\n        HttpKernelInterface $kernel,\n        Request $request,\n        private Response $response,\n    ) {\n        parent::__construct($kernel, $request, HttpKernelInterface::MAIN_REQUEST);\n    }\n\n    public function getResponse(): Response\n    {\n        return $this->response;\n    }\n}\n"
  },
  {
    "path": "Event/ViewEvent.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Event;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\n\n/**\n * Allows to create a response for the return value of a controller.\n *\n * Call setResponse() to set the response that will be returned for the\n * current request. The propagation of this event is stopped as soon as a\n * response is set.\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nfinal class ViewEvent extends RequestEvent\n{\n    public readonly ?ControllerArgumentsMetadata $controllerMetadata;\n\n    /**\n     * @deprecated since Symfony 8.1, use $controllerMetadata instead\n     */\n    public private(set) ?ControllerArgumentsEvent $controllerArgumentsEvent {\n        get {\n            trigger_deprecation('symfony/http-kernel', '8.1', 'Accessing the \"controllerArgumentsEvent\" property of the \"%s\" class is deprecated. Use \"controllerMetadata\" instead.', __CLASS__);\n\n            if (!$m = $this->controllerMetadata) {\n                return null;\n            }\n\n            return $this->controllerArgumentsEvent ??= new ControllerArgumentsEvent($this->getKernel(), \\Closure::bind(fn () => $this->controllerEvent, $m, ControllerMetadata::class)(), $m->getArguments(), $this->getRequest(), $this->getRequestType());\n        }\n    }\n\n    public function __construct(\n        HttpKernelInterface $kernel,\n        Request $request,\n        int $requestType,\n        private mixed $controllerResult,\n        ControllerArgumentsMetadata|ControllerArgumentsEvent|null $controllerMetadata = null,\n    ) {\n        if ($controllerMetadata instanceof ControllerArgumentsEvent) {\n            trigger_deprecation('symfony/http-kernel', '8.1', 'Passing a ControllerArgumentsEvent to the ViewEvent constructor is deprecated. Pass a ControllerArgumentsMetadata instance instead.');\n            $this->controllerArgumentsEvent = $controllerMetadata;\n            $controllerEvent = \\Closure::bind(fn () => $this->controllerEvent, $controllerMetadata, ControllerArgumentsEvent::class)();\n            $controllerMetadata = new ControllerArgumentsMetadata($controllerEvent, $controllerMetadata);\n        }\n        $this->controllerMetadata = $controllerMetadata;\n\n        parent::__construct($kernel, $request, $requestType);\n    }\n\n    public function getControllerResult(): mixed\n    {\n        return $this->controllerResult;\n    }\n\n    public function setControllerResult(mixed $controllerResult): void\n    {\n        $this->controllerResult = $controllerResult;\n    }\n}\n"
  },
  {
    "path": "EventListener/AbstractSessionListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Psr\\Container\\ContainerInterface;\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpFoundation\\Cookie;\nuse Symfony\\Component\\HttpFoundation\\Session\\Session;\nuse Symfony\\Component\\HttpFoundation\\Session\\SessionInterface;\nuse Symfony\\Component\\HttpFoundation\\Session\\SessionUtils;\nuse Symfony\\Component\\HttpKernel\\Event\\RequestEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\Exception\\UnexpectedSessionUsageException;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * Sets the session onto the request on the \"kernel.request\" event and saves\n * it on the \"kernel.response\" event.\n *\n * In addition, if the session has been started it overrides the Cache-Control\n * header in such a way that all caching is disabled in that case.\n * If you have a scenario where caching responses with session information in\n * them makes sense, you can disable this behaviour by setting the header\n * AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER on the response.\n *\n * @author Johannes M. Schmitt <schmittjoh@gmail.com>\n * @author Tobias Schultze <http://tobion.de>\n */\nabstract class AbstractSessionListener implements EventSubscriberInterface, ResetInterface\n{\n    public const NO_AUTO_CACHE_CONTROL_HEADER = 'Symfony-Session-NoAutoCacheControl';\n\n    /**\n     * @param array<string, mixed> $sessionOptions\n     *\n     * @internal\n     */\n    public function __construct(\n        private ?ContainerInterface $container = null,\n        private bool $debug = false,\n        private array $sessionOptions = [],\n    ) {\n    }\n\n    /**\n     * @internal\n     */\n    public function onKernelRequest(RequestEvent $event): void\n    {\n        if (!$event->isMainRequest()) {\n            return;\n        }\n\n        $request = $event->getRequest();\n        if (!$request->hasSession()) {\n            $request->setSessionFactory(function () use ($request) {\n                // Prevent calling `$this->getSession()` twice in case the Request (and the below factory) is cloned\n                static $sess;\n\n                if (!$sess) {\n                    $sess = $this->getSession();\n                    $request->setSession($sess);\n\n                    /*\n                     * For supporting sessions in php runtime with runners like roadrunner or swoole, the session\n                     * cookie needs to be read from the cookie bag and set on the session storage.\n                     *\n                     * Do not set it when a native php session is active.\n                     */\n                    if ($sess && !$sess->isStarted() && \\PHP_SESSION_ACTIVE !== session_status()) {\n                        $sessionId = $sess->getId() ?: $request->cookies->get($sess->getName(), '');\n                        $sess->setId($sessionId);\n                    }\n                }\n\n                return $sess;\n            });\n        }\n    }\n\n    /**\n     * @internal\n     */\n    public function onKernelResponse(ResponseEvent $event): void\n    {\n        if (!$event->isMainRequest()) {\n            return;\n        }\n\n        $response = $event->getResponse();\n        $autoCacheControl = !$response->headers->has(self::NO_AUTO_CACHE_CONTROL_HEADER);\n        // Always remove the internal header if present\n        $response->headers->remove(self::NO_AUTO_CACHE_CONTROL_HEADER);\n        if (!$event->getRequest()->hasSession(true)) {\n            return;\n        }\n        $session = $event->getRequest()->getSession();\n\n        if ($session->isStarted()) {\n            /*\n             * Saves the session, in case it is still open, before sending the response/headers.\n             *\n             * This ensures several things in case the developer did not save the session explicitly:\n             *\n             *  * If a session save handler without locking is used, it ensures the data is available\n             *    on the next request, e.g. after a redirect. PHPs auto-save at script end via\n             *    session_register_shutdown is executed after fastcgi_finish_request. So in this case\n             *    the data could be missing the next request because it might not be saved the moment\n             *    the new request is processed.\n             *  * A locking save handler (e.g. the native 'files') circumvents concurrency problems like\n             *    the one above. But by saving the session before long-running things in the terminate event,\n             *    we ensure the session is not blocked longer than needed.\n             *  * When regenerating the session ID no locking is involved in PHPs session design. See\n             *    https://bugs.php.net/61470 for a discussion. So in this case, the session must\n             *    be saved anyway before sending the headers with the new session ID. Otherwise session\n             *    data could get lost again for concurrent requests with the new ID. One result could be\n             *    that you get logged out after just logging in.\n             *\n             * This listener should be executed as one of the last listeners, so that previous listeners\n             * can still operate on the open session. This prevents the overhead of restarting it.\n             * Listeners after closing the session can still work with the session as usual because\n             * Symfonys session implementation starts the session on demand. So writing to it after\n             * it is saved will just restart it.\n             */\n            $session->save();\n\n            /*\n             * For supporting sessions in php runtime with runners like roadrunner or swoole the session\n             * cookie need to be written on the response object and should not be written by PHP itself.\n             */\n            $sessionName = $session->getName();\n            $sessionId = $session->getId();\n            $sessionOptions = $this->getSessionOptions($this->sessionOptions);\n            $sessionCookiePath = $sessionOptions['cookie_path'] ?? '/';\n            $sessionCookieDomain = $sessionOptions['cookie_domain'] ?? null;\n            $sessionCookieSecure = $sessionOptions['cookie_secure'] ?? false;\n            $sessionCookieHttpOnly = $sessionOptions['cookie_httponly'] ?? true;\n            $sessionCookieSameSite = $sessionOptions['cookie_samesite'] ?? Cookie::SAMESITE_LAX;\n            $sessionUseCookies = $sessionOptions['use_cookies'] ?? true;\n\n            SessionUtils::popSessionCookie($sessionName, $sessionId);\n\n            if ($sessionUseCookies) {\n                $request = $event->getRequest();\n                $requestSessionCookieId = $request->cookies->get($sessionName);\n\n                $isSessionEmpty = ($session instanceof Session ? $session->isEmpty() : !$session->all()) && empty($_SESSION); // checking $_SESSION to keep compatibility with native sessions\n                if ($requestSessionCookieId && $isSessionEmpty) {\n                    // PHP internally sets the session cookie value to \"deleted\" when setcookie() is called with empty string $value argument\n                    // which happens in \\Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\AbstractSessionHandler::destroy\n                    // when the session gets invalidated (for example on logout) so we must handle this case here too\n                    // otherwise we would send two Set-Cookie headers back with the response\n                    SessionUtils::popSessionCookie($sessionName, 'deleted');\n                    $response->headers->clearCookie(\n                        $sessionName,\n                        $sessionCookiePath,\n                        $sessionCookieDomain,\n                        $sessionCookieSecure,\n                        $sessionCookieHttpOnly,\n                        $sessionCookieSameSite\n                    );\n                } elseif ($sessionId !== $requestSessionCookieId && !$isSessionEmpty) {\n                    $expire = 0;\n                    $lifetime = $sessionOptions['cookie_lifetime'] ?? null;\n                    if ($lifetime) {\n                        $expire = time() + $lifetime;\n                    }\n\n                    $response->headers->setCookie(\n                        Cookie::create(\n                            $sessionName,\n                            $sessionId,\n                            $expire,\n                            $sessionCookiePath,\n                            $sessionCookieDomain,\n                            $sessionCookieSecure,\n                            $sessionCookieHttpOnly,\n                            false,\n                            $sessionCookieSameSite\n                        )\n                    );\n                }\n            }\n        }\n\n        if ($session instanceof Session ? 0 === $session->getUsageIndex() : !$session->isStarted()) {\n            return;\n        }\n\n        if ($autoCacheControl) {\n            $maxAge = $response->headers->hasCacheControlDirective('public') ? 0 : (int) $response->getMaxAge();\n            $response\n                ->setExpires(new \\DateTimeImmutable('+'.$maxAge.' seconds'))\n                ->setPrivate()\n                ->setMaxAge($maxAge)\n                ->headers->addCacheControlDirective('must-revalidate');\n        }\n\n        if (!$event->getRequest()->attributes->get('_stateless', false)) {\n            return;\n        }\n\n        if ($this->debug) {\n            throw new UnexpectedSessionUsageException('Session was used while the request was declared stateless.');\n        }\n\n        if ($this->container->has('logger')) {\n            $this->container->get('logger')->warning('Session was used while the request was declared stateless.');\n        }\n    }\n\n    /**\n     * @internal\n     */\n    public function onSessionUsage(): void\n    {\n        if (!$this->debug) {\n            return;\n        }\n\n        if ($this->container?->has('session_collector')) {\n            $this->container->get('session_collector')();\n        }\n\n        if (!$requestStack = $this->container?->has('request_stack') ? $this->container->get('request_stack') : null) {\n            return;\n        }\n\n        $stateless = false;\n        $clonedRequestStack = clone $requestStack;\n        while (null !== ($request = $clonedRequestStack->pop()) && !$stateless) {\n            $stateless = $request->attributes->get('_stateless');\n        }\n\n        if (!$stateless) {\n            return;\n        }\n\n        if (!$session = $requestStack->getCurrentRequest()->getSession()) {\n            return;\n        }\n\n        if ($session->isStarted()) {\n            $session->save();\n        }\n\n        throw new UnexpectedSessionUsageException('Session was used while the request was declared stateless.');\n    }\n\n    /**\n     * @internal\n     */\n    public static function getSubscribedEvents(): array\n    {\n        return [\n            KernelEvents::REQUEST => ['onKernelRequest', 128],\n            // low priority to come after regular response listeners\n            KernelEvents::RESPONSE => ['onKernelResponse', -1000],\n        ];\n    }\n\n    /**\n     * @internal\n     */\n    public function reset(): void\n    {\n        if (\\PHP_SESSION_ACTIVE === session_status()) {\n            session_abort();\n        }\n\n        session_unset();\n        $_SESSION = [];\n\n        if (!headers_sent()) { // session id can only be reset when no headers were so we check for headers_sent first\n            session_id('');\n        }\n    }\n\n    /**\n     * Gets the session object.\n     *\n     * @internal\n     */\n    abstract protected function getSession(): ?SessionInterface;\n\n    private function getSessionOptions(array $sessionOptions): array\n    {\n        $mergedSessionOptions = [];\n\n        foreach (session_get_cookie_params() as $key => $value) {\n            $mergedSessionOptions['cookie_'.$key] = $value;\n        }\n\n        foreach ($sessionOptions as $key => $value) {\n            // do the same logic as in the NativeSessionStorage\n            if ('cookie_secure' === $key && 'auto' === $value) {\n                continue;\n            }\n            $mergedSessionOptions[$key] = $value;\n        }\n\n        return $mergedSessionOptions;\n    }\n}\n"
  },
  {
    "path": "EventListener/AddRequestFormatsListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpKernel\\Event\\RequestEvent;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\n\n/**\n * Adds configured formats to each request.\n *\n * @author Gildas Quemener <gildas.quemener@gmail.com>\n *\n * @final\n */\nclass AddRequestFormatsListener implements EventSubscriberInterface\n{\n    public function __construct(\n        private array $formats,\n    ) {\n    }\n\n    /**\n     * Adds request formats.\n     */\n    public function onKernelRequest(RequestEvent $event): void\n    {\n        $request = $event->getRequest();\n        foreach ($this->formats as $format => $mimeTypes) {\n            $request->setFormat($format, $mimeTypes);\n        }\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        return [KernelEvents::REQUEST => ['onKernelRequest', 100]];\n    }\n}\n"
  },
  {
    "path": "EventListener/CacheAttributeListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\ExpressionLanguage\\Expression;\nuse Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage;\nuse Symfony\\Component\\HttpFoundation\\HeaderBag;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Attribute\\Cache;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerAttributeEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\n\n/**\n * Handles HTTP cache headers configured via the Cache attribute.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass CacheAttributeListener implements EventSubscriberInterface\n{\n    public function __construct(\n        private ?ExpressionLanguage $expressionLanguage = null,\n    ) {\n    }\n\n    public function onKernelControllerAttribute(ControllerAttributeEvent $event): void\n    {\n        $cache = $event->attribute;\n        $kernelEvent = $event->kernelEvent;\n        $request = $event->kernelEvent->getRequest();\n\n        if ($kernelEvent instanceof ControllerArgumentsEvent) {\n            if (null !== $variables = $this->getVariables($cache, $request, $kernelEvent)) {\n                $cache->variables = $variables;\n            }\n            $this->processAttributeBeforeController($cache, $request, $kernelEvent);\n\n            return;\n        }\n\n        if ($kernelEvent instanceof ResponseEvent) {\n            $response = $kernelEvent->getResponse();\n\n            // http://tools.ietf.org/html/draft-ietf-httpbis-p4-conditional-12#section-3.1\n            if (!\\in_array($response->getStatusCode(), [200, 203, 300, 301, 302, 304, 404, 410], true)) {\n                return;\n            }\n\n            $this->processAttributeAfterController($cache, $request, $response);\n\n            return;\n        }\n    }\n\n    /**\n     * @internal since Symfony 8.1, use onKernelControllerAttribute() instead\n     */\n    public function onKernelControllerArguments(ControllerArgumentsEvent $event): void\n    {\n        $request = $event->getRequest();\n\n        /** @var Cache[] $attributes */\n        if (!$attributes = $request->attributes->get('_cache') ?? $event->getAttributes(Cache::class)) {\n            return;\n        }\n\n        $request->attributes->set('_cache', $attributes);\n        $variables = null;\n\n        foreach ($attributes as $cache) {\n            if (null !== $variables ??= $this->getVariables($cache, $request, $event)) {\n                $cache->variables = $variables;\n            }\n            $this->processAttributeBeforeController($cache, $request, $event);\n        }\n    }\n\n    /**\n     * @internal since Symfony 8.1, use onKernelControllerAttribute() instead\n     */\n    public function onKernelResponse(ResponseEvent $event): void\n    {\n        $request = $event->getRequest();\n\n        /** @var Cache[] $attributes */\n        if (!\\is_array($attributes = $request->attributes->get('_cache'))) {\n            return;\n        }\n        $response = $event->getResponse();\n\n        // http://tools.ietf.org/html/draft-ietf-httpbis-p4-conditional-12#section-3.1\n        if (!\\in_array($response->getStatusCode(), [200, 203, 300, 301, 302, 304, 404, 410], true)) {\n            return;\n        }\n\n        $hasVary = null;\n        $hasCacheControlDirective = null;\n\n        for ($i = \\count($attributes) - 1; 0 <= $i; --$i) {\n            $this->processAttributeAfterController($attributes[$i], $request, $response, $hasVary, $hasCacheControlDirective);\n        }\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        if (!class_exists(ControllerAttributesListener::class, false)) {\n            return [\n                KernelEvents::CONTROLLER_ARGUMENTS => ['onKernelControllerArguments', 10],\n                KernelEvents::RESPONSE => ['onKernelResponse', -10],\n            ];\n        }\n\n        return [\n            KernelEvents::CONTROLLER_ARGUMENTS.'.'.Cache::class => 'onKernelControllerAttribute',\n            KernelEvents::RESPONSE.'.'.Cache::class => 'onKernelControllerAttribute',\n        ];\n    }\n\n    public function reset(): void\n    {\n    }\n\n    private function processAttributeBeforeController(Cache $cache, Request $request, ControllerArgumentsEvent $event): void\n    {\n        if (!\\is_bool($cache->if)) {\n            if (!\\is_bool($if = $this->evaluate($cache->if, $cache->variables))) {\n                throw new \\TypeError(\\sprintf('The value of the \"$if\" option of the \"%s\" attribute must evaluate to a boolean, \"%s\" given.', Cache::class, get_debug_type($if)));\n            }\n\n            $cache->if = $if;\n        }\n\n        if (!$cache->if) {\n            return;\n        }\n\n        $response = null;\n\n        if (null !== $cache->lastModified && !$cache->lastModified instanceof \\DateTimeInterface) {\n            $lastModified = $this->evaluate($cache->lastModified, $cache->variables);\n            ($response ??= new Response())->setLastModified($lastModified);\n            $cache->lastModified = $lastModified;\n        }\n\n        if (null !== $cache->etag) {\n            $etag = hash('sha256', $this->evaluate($cache->etag, $cache->variables));\n            ($response ??= new Response())->setEtag($etag);\n            $cache->etag = $etag;\n        }\n\n        if ($response?->isNotModified($request)) {\n            $event->setController(static fn () => $response);\n            $event->stopPropagation();\n        }\n    }\n\n    private function processAttributeAfterController(Cache $cache, Request $request, Response $response, ?bool &$hasVary = null, ?callable &$hasCacheControlDirective = null): void\n    {\n        if (!$cache->if) {\n            return;\n        }\n\n        // Check if the response has a Vary header that should be considered, ignoring cases where\n        // it's only 'Accept-Language' and the request has the '_vary_by_language' attribute\n        $hasVary ??= ['Accept-Language'] === $response->getVary() ? !$request->attributes->get('_vary_by_language') : $response->hasVary();\n        // Check if cache-control directive was set manually in cacheControl (not auto computed)\n        $hasCacheControlDirective ??= new class($response->headers) extends HeaderBag {\n            public function __construct(private parent $headerBag)\n            {\n            }\n\n            public function __invoke(string $key): bool\n            {\n                return \\array_key_exists($key, $this->headerBag->cacheControl);\n            }\n        };\n\n        if (null !== $cache->lastModified && !$response->headers->has('Last-Modified')) {\n            $response->setLastModified($cache->lastModified);\n        }\n\n        if (null !== $cache->etag && !$response->headers->has('ETag')) {\n            $response->setEtag($cache->etag);\n        }\n\n        if (null !== $cache->smaxage && !$hasCacheControlDirective('s-maxage')) {\n            $response->setSharedMaxAge($this->toSeconds($cache->smaxage));\n        }\n\n        if ($cache->mustRevalidate) {\n            $response->headers->addCacheControlDirective('must-revalidate');\n        }\n\n        if (null !== $cache->maxage && !$hasCacheControlDirective('max-age')) {\n            $response->setMaxAge($this->toSeconds($cache->maxage));\n        }\n\n        if (null !== $cache->maxStale && !$hasCacheControlDirective('max-stale')) {\n            $response->headers->addCacheControlDirective('max-stale', $this->toSeconds($cache->maxStale));\n        }\n\n        if (null !== $cache->staleWhileRevalidate && !$hasCacheControlDirective('stale-while-revalidate')) {\n            $response->headers->addCacheControlDirective('stale-while-revalidate', $this->toSeconds($cache->staleWhileRevalidate));\n        }\n\n        if (null !== $cache->staleIfError && !$hasCacheControlDirective('stale-if-error')) {\n            $response->headers->addCacheControlDirective('stale-if-error', $this->toSeconds($cache->staleIfError));\n        }\n\n        if (null !== $cache->expires && !$response->headers->has('Expires')) {\n            $response->setExpires(new \\DateTimeImmutable('@'.strtotime($cache->expires, time())));\n        }\n\n        if (!$hasVary && $cache->vary) {\n            $response->setVary($cache->vary, false);\n        }\n\n        $hasPublicOrPrivateCacheControlDirective = \\is_bool($cache->public) && ($hasCacheControlDirective('public') || $hasCacheControlDirective('private'));\n\n        if (true === $cache->public && !$hasPublicOrPrivateCacheControlDirective) {\n            $response->setPublic();\n        }\n\n        if (false === $cache->public && !$hasPublicOrPrivateCacheControlDirective) {\n            $response->setPrivate();\n        }\n\n        if (true === $cache->noStore) {\n            $response->headers->addCacheControlDirective('no-store');\n        }\n\n        if (false === $cache->noStore) {\n            $response->headers->removeCacheControlDirective('no-store');\n        }\n    }\n\n    private function getVariables(Cache $cache, Request $request, ControllerArgumentsEvent $event): ?array\n    {\n        if (\\is_bool($cache->if) && null === $cache->lastModified && null === $cache->etag) {\n            return null;\n        }\n\n        $controller = $event->getController();\n        $controller = match (true) {\n            \\is_object($controller) && !$controller instanceof \\Closure => $controller,\n            \\is_array($controller) && \\is_object($controller[0]) => $controller[0],\n            default => null,\n        };\n\n        return array_merge([\n            'request' => $request,\n            'args' => $arguments = $event->getNamedArguments(),\n            'this' => $controller,\n        ], $request->attributes->all(), $arguments);\n    }\n\n    private function evaluate(string|Expression|\\Closure $closureOrExpression, array $variables): mixed\n    {\n        if ($closureOrExpression instanceof \\Closure) {\n            return $closureOrExpression($variables['args'], $variables['request'], $variables['this']);\n        }\n\n        return $this->getExpressionLanguage()->evaluate($closureOrExpression, $variables);\n    }\n\n    private function getExpressionLanguage(): ExpressionLanguage\n    {\n        return $this->expressionLanguage ??= class_exists(ExpressionLanguage::class)\n            ? new ExpressionLanguage()\n            : throw new \\LogicException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed. Try running \"composer require symfony/expression-language\".');\n    }\n\n    private function toSeconds(int|string $time): int\n    {\n        if (!is_numeric($time)) {\n            $now = time();\n            $time = strtotime($time, $now) - $now;\n        }\n\n        return $time;\n    }\n}\n"
  },
  {
    "path": "EventListener/ControllerAttributesListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerAttributeEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\KernelEvent;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\nuse Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface;\n\n// Help opcache.preload discover always-needed symbols\nclass_exists(ControllerAttributeEvent::class);\nclass_exists(ExpressionLanguage::class);\n\n/**\n * Dispatches events for controller attributes.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass ControllerAttributesListener implements EventSubscriberInterface\n{\n    /**\n     * @param array<string, array<class-string, true>> $attributesWithListenersByEvent\n     */\n    public function __construct(\n        private readonly array $attributesWithListenersByEvent,\n        private ?ExpressionLanguage $expressionLanguage = null,\n    ) {\n        $this->expressionLanguage ??= class_exists(ExpressionLanguage::class, false) ? new ExpressionLanguage() : null;\n    }\n\n    private static array $attributeHierarchyCache = [];\n\n    public function beforeController(ControllerEvent|ControllerArgumentsEvent $event, string $eventName, EventDispatcherInterface $dispatcher): void\n    {\n        $controller = $event->getController();\n\n        dispatch_attributes:\n        foreach ($event->getAttributes('*') as $attribute) {\n            if (!$attributeEventNames = $this->getAttributeEventNames($attribute, $eventName)) {\n                continue;\n            }\n\n            foreach ($attributeEventNames as $attributeEventName) {\n                $dispatcher->dispatch(new ControllerAttributeEvent($attribute, $event, $this->expressionLanguage), $attributeEventName);\n\n                if ($event->isPropagationStopped()) {\n                    return;\n                }\n            }\n\n            $c = $event->getController();\n            if ($c instanceof \\Closure ? $c != $controller : $c !== $controller) {\n                $controller = $c;\n                goto dispatch_attributes;\n            }\n        }\n    }\n\n    public function afterController(KernelEvent $event, string $eventName, EventDispatcherInterface $dispatcher): void\n    {\n        $attributes = $event->controllerMetadata?->getAttributes('*') ?? [];\n\n        for ($i = \\count($attributes) - 1; $i >= 0; --$i) {\n            $attribute = $attributes[$i];\n            $attributeEventNames = $this->getAttributeEventNames($attribute, $eventName);\n\n            for ($j = \\count($attributeEventNames) - 1; $j >= 0; --$j) {\n                $dispatcher->dispatch(new ControllerAttributeEvent($attribute, $event, $this->expressionLanguage), $attributeEventNames[$j]);\n\n                if ($event->isPropagationStopped()) {\n                    return;\n                }\n            }\n        }\n    }\n\n    private function getAttributeEventNames(object $attribute, string $eventName): array\n    {\n        if (!$attributesWithListeners = $this->attributesWithListenersByEvent[$eventName] ?? []) {\n            return [];\n        }\n\n        $names = [];\n        $class = $attribute::class;\n        $hierarchy = self::$attributeHierarchyCache[$class] ??= [$class => $class] + class_parents($class) + class_implements($class);\n\n        foreach ($hierarchy as $class) {\n            if (isset($attributesWithListeners[$class])) {\n                $names[] = $eventName.'.'.$class;\n            }\n        }\n\n        return $names;\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        return [\n            KernelEvents::CONTROLLER => ['beforeController', -10000],\n            KernelEvents::CONTROLLER_ARGUMENTS => ['beforeController', -10000],\n            KernelEvents::VIEW => ['afterController', 10000],\n            KernelEvents::RESPONSE => ['afterController', 10000],\n            KernelEvents::EXCEPTION => ['afterController', 10000],\n            KernelEvents::FINISH_REQUEST => ['afterController', 10000],\n        ];\n    }\n}\n"
  },
  {
    "path": "EventListener/DebugHandlersListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Symfony\\Component\\Console\\ConsoleEvents;\nuse Symfony\\Component\\Console\\Event\\ConsoleEvent;\nuse Symfony\\Component\\Console\\Output\\ConsoleOutputInterface;\nuse Symfony\\Component\\ErrorHandler\\ErrorHandler;\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpKernel\\Event\\KernelEvent;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\n\n/**\n * Sets an exception handler.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @final\n *\n * @internal\n */\nclass DebugHandlersListener implements EventSubscriberInterface\n{\n    private string|object|null $earlyHandler;\n    private ?\\Closure $exceptionHandler;\n    private bool $webMode;\n    private bool $firstCall = true;\n    private bool $hasTerminatedWithException = false;\n\n    /**\n     * @param callable|null $exceptionHandler A handler that must support \\Throwable instances that will be called on Exception\n     */\n    public function __construct(?callable $exceptionHandler = null, ?bool $webMode = null)\n    {\n        $handler = set_exception_handler('var_dump');\n        $this->earlyHandler = \\is_array($handler) ? $handler[0] : null;\n        restore_exception_handler();\n\n        $this->exceptionHandler = null === $exceptionHandler ? null : $exceptionHandler(...);\n        $this->webMode = $webMode ?? !\\in_array(\\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true);\n    }\n\n    /**\n     * Configures the error handler.\n     */\n    public function configure(?object $event = null): void\n    {\n        if ($event instanceof ConsoleEvent && $this->webMode) {\n            return;\n        }\n        if (!$event instanceof KernelEvent ? !$this->firstCall : !$event->isMainRequest()) {\n            return;\n        }\n        $this->firstCall = $this->hasTerminatedWithException = false;\n        $hasRun = null;\n\n        if (!$this->exceptionHandler) {\n            if ($event instanceof KernelEvent) {\n                if (method_exists($kernel = $event->getKernel(), 'terminateWithException')) {\n                    $request = $event->getRequest();\n                    $hasRun = &$this->hasTerminatedWithException;\n                    $this->exceptionHandler = static function (\\Throwable $e) use ($kernel, $request, &$hasRun) {\n                        if ($hasRun) {\n                            throw $e;\n                        }\n\n                        $hasRun = true;\n                        $kernel->terminateWithException($e, $request);\n                    };\n                }\n            } elseif ($event instanceof ConsoleEvent && $app = $event->getCommand()->getApplication()) {\n                $output = $event->getOutput();\n                if ($output instanceof ConsoleOutputInterface) {\n                    $output = $output->getErrorOutput();\n                }\n                $this->exceptionHandler = static function (\\Throwable $e) use ($app, $output) {\n                    $app->renderThrowable($e, $output);\n                };\n            }\n        }\n        if ($this->exceptionHandler) {\n            $handler = set_exception_handler('var_dump');\n            $handler = \\is_array($handler) ? $handler[0] : null;\n            restore_exception_handler();\n\n            if (!$handler instanceof ErrorHandler) {\n                $handler = $this->earlyHandler;\n            }\n\n            if ($handler instanceof ErrorHandler) {\n                $handler->setExceptionHandler($this->exceptionHandler);\n                if (null !== $hasRun) {\n                    $throwAt = $handler->throwAt(0) | \\E_ERROR | \\E_CORE_ERROR | \\E_COMPILE_ERROR | \\E_USER_ERROR | \\E_RECOVERABLE_ERROR | \\E_PARSE;\n                    $loggers = [];\n\n                    foreach ($handler->setLoggers([]) as $type => $log) {\n                        if ($type & $throwAt) {\n                            $loggers[$type] = [null, $log[1]];\n                        }\n                    }\n\n                    // Assume $kernel->terminateWithException() will log uncaught exceptions appropriately\n                    $handler->setLoggers($loggers);\n                }\n            }\n            $this->exceptionHandler = null;\n        }\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        $events = [KernelEvents::REQUEST => ['configure', 2048]];\n\n        if (\\defined('Symfony\\Component\\Console\\ConsoleEvents::COMMAND')) {\n            $events[ConsoleEvents::COMMAND] = ['configure', 2048];\n        }\n\n        return $events;\n    }\n}\n"
  },
  {
    "path": "EventListener/DisallowRobotsIndexingListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\n\n/**\n * Ensures that the application is not indexed by search engines.\n *\n * @author Gary PEGEOT <garypegeot@gmail.com>\n */\nclass DisallowRobotsIndexingListener implements EventSubscriberInterface\n{\n    private const HEADER_NAME = 'X-Robots-Tag';\n\n    public function onResponse(ResponseEvent $event): void\n    {\n        if (!$event->getResponse()->headers->has(static::HEADER_NAME)) {\n            $event->getResponse()->headers->set(static::HEADER_NAME, 'noindex');\n        }\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        return [\n            KernelEvents::RESPONSE => ['onResponse', -255],\n        ];\n    }\n}\n"
  },
  {
    "path": "EventListener/DumpListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Symfony\\Component\\Console\\ConsoleEvents;\nuse Symfony\\Component\\Console\\Event\\ConsoleCommandEvent;\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\VarDumper\\Cloner\\ClonerInterface;\nuse Symfony\\Component\\VarDumper\\Dumper\\DataDumperInterface;\nuse Symfony\\Component\\VarDumper\\Server\\Connection;\nuse Symfony\\Component\\VarDumper\\VarDumper;\n\n/**\n * Configures dump() handler.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass DumpListener implements EventSubscriberInterface\n{\n    /**\n     * @param ?DataDumperInterface $profilerDumper The dumper to use when CLI profiling is enabled.\n     *                                             If null, the default $dumper will be used instead.\n     */\n    public function __construct(\n        private ClonerInterface $cloner,\n        private DataDumperInterface $dumper,\n        private ?Connection $connection = null,\n        private ?DataDumperInterface $profilerDumper = null,\n    ) {\n    }\n\n    public function configure(?ConsoleCommandEvent $event = null): void\n    {\n        $input = $event?->getInput();\n\n        $cloner = $this->cloner;\n        $dumper = !$this->profilerDumper || !$input?->hasOption('profile') || !$input?->getOption('profile') ? $this->dumper : $this->profilerDumper;\n        $connection = $this->connection;\n\n        VarDumper::setHandler(static function ($var, ?string $label = null) use ($cloner, $dumper, $connection) {\n            $data = $cloner->cloneVar($var);\n            if (null !== $label) {\n                $data = $data->withContext(['label' => $label]);\n            }\n\n            if (!$connection || !$connection->write($data)) {\n                $dumper->dump($data);\n            }\n        });\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        if (!class_exists(ConsoleEvents::class)) {\n            return [];\n        }\n\n        // Register early to have a working dump() as early as possible\n        return [ConsoleEvents::COMMAND => ['configure', 1024]];\n    }\n}\n"
  },
  {
    "path": "EventListener/ErrorListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Psr\\Log\\LoggerInterface;\nuse Psr\\Log\\LogLevel;\nuse Symfony\\Component\\ErrorHandler\\ErrorHandler;\nuse Symfony\\Component\\ErrorHandler\\Exception\\FlattenException;\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Attribute\\WithHttpStatus;\nuse Symfony\\Component\\HttpKernel\\Attribute\\WithLogLevel;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ExceptionEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpExceptionInterface;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\nuse Symfony\\Component\\HttpKernel\\Log\\DebugLoggerConfigurator;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass ErrorListener implements EventSubscriberInterface\n{\n    /**\n     * @param array<class-string, array{log_level: string|null, status_code: int<100,599>|null, log_channel: string|null}> $exceptionsMapping\n     */\n    public function __construct(\n        protected string|object|array|null $controller,\n        protected ?LoggerInterface $logger = null,\n        protected bool $debug = false,\n        protected array $exceptionsMapping = [],\n        protected array $loggers = [],\n    ) {\n    }\n\n    public function logKernelException(ExceptionEvent $event): void\n    {\n        $throwable = $event->getThrowable();\n        $logLevel = $this->resolveLogLevel($throwable);\n        $logChannel = $this->resolveLogChannel($throwable);\n\n        foreach ($this->exceptionsMapping as $class => $config) {\n            if (!$throwable instanceof $class || !$config['status_code']) {\n                continue;\n            }\n            if (!$throwable instanceof HttpExceptionInterface || $throwable->getStatusCode() !== $config['status_code']) {\n                $headers = $throwable instanceof HttpExceptionInterface ? $throwable->getHeaders() : [];\n                $throwable = HttpException::fromStatusCode($config['status_code'], $throwable->getMessage(), $throwable, $headers);\n                $event->setThrowable($throwable);\n            }\n            break;\n        }\n\n        // There's no specific status code defined in the configuration for this exception\n        if (!$throwable instanceof HttpExceptionInterface && $withHttpStatus = $this->getInheritedAttribute($throwable::class, WithHttpStatus::class)) {\n            $throwable = HttpException::fromStatusCode($withHttpStatus->statusCode, $throwable->getMessage(), $throwable, $withHttpStatus->headers);\n            $event->setThrowable($throwable);\n        }\n\n        $e = FlattenException::createFromThrowable($throwable);\n\n        $this->logException($throwable, \\sprintf('Uncaught PHP Exception %s: \"%s\" at %s line %s', $e->getClass(), $e->getMessage(), basename($e->getFile()), $e->getLine()), $logLevel, $logChannel);\n    }\n\n    public function onKernelException(ExceptionEvent $event): void\n    {\n        if (null === $this->controller) {\n            return;\n        }\n\n        if (!$this->debug && $event->isKernelTerminating()) {\n            return;\n        }\n\n        $throwable = $event->getThrowable();\n\n        $exceptionHandler = set_exception_handler('var_dump');\n        restore_exception_handler();\n\n        if (\\is_array($exceptionHandler) && $exceptionHandler[0] instanceof ErrorHandler) {\n            $throwable = $exceptionHandler[0]->enhanceError($event->getThrowable());\n        }\n\n        $request = $this->duplicateRequest($throwable, $event->getRequest());\n\n        try {\n            $response = $event->getKernel()->handle($request, HttpKernelInterface::SUB_REQUEST, false);\n        } catch (\\Exception $e) {\n            $f = FlattenException::createFromThrowable($e);\n\n            $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()));\n\n            $prev = $e;\n            do {\n                if ($throwable === $wrapper = $prev) {\n                    throw $e;\n                }\n            } while ($prev = $wrapper->getPrevious());\n\n            $prev = new \\ReflectionProperty($wrapper instanceof \\Exception ? \\Exception::class : \\Error::class, 'previous');\n            $prev->setValue($wrapper, $throwable);\n\n            throw $e;\n        }\n\n        $event->setResponse($response);\n\n        if ($this->debug) {\n            $event->getRequest()->attributes->set('_remove_csp_headers', true);\n        }\n    }\n\n    public function removeCspHeader(ResponseEvent $event): void\n    {\n        if ($this->debug && $event->getRequest()->attributes->get('_remove_csp_headers', false)) {\n            $event->getResponse()->headers->remove('Content-Security-Policy');\n        }\n    }\n\n    public function onControllerArguments(ControllerArgumentsEvent $event): void\n    {\n        $e = $event->getRequest()->attributes->get('exception');\n\n        if (!$e instanceof \\Throwable || false === $k = array_search($e, $event->getArguments(), true)) {\n            return;\n        }\n\n        $r = new \\ReflectionFunction($event->getController()(...));\n        $r = $r->getParameters()[$k] ?? null;\n\n        if ($r && (!($r = $r->getType()) instanceof \\ReflectionNamedType || FlattenException::class === $r->getName())) {\n            $arguments = $event->getArguments();\n            $arguments[$k] = FlattenException::createFromThrowable($e);\n            $event->setArguments($arguments);\n        }\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        return [\n            KernelEvents::CONTROLLER_ARGUMENTS => 'onControllerArguments',\n            KernelEvents::EXCEPTION => [\n                ['logKernelException', 0],\n                ['onKernelException', -128],\n            ],\n            KernelEvents::RESPONSE => ['removeCspHeader', -128],\n        ];\n    }\n\n    protected function logException(\\Throwable $exception, string $message, ?string $logLevel = null, ?string $logChannel = null): void\n    {\n        $logChannel ??= $this->resolveLogChannel($exception);\n        $logLevel ??= $this->resolveLogLevel($exception);\n\n        if (!$logger = $this->getLogger($logChannel)) {\n            return;\n        }\n\n        $logger->log($logLevel, $message, ['exception' => $exception]);\n    }\n\n    /**\n     * Resolves the level to be used when logging the exception.\n     */\n    private function resolveLogLevel(\\Throwable $throwable): string\n    {\n        foreach ($this->exceptionsMapping as $class => $config) {\n            if ($throwable instanceof $class && $config['log_level']) {\n                return $config['log_level'];\n            }\n        }\n\n        if ($withLogLevel = $this->getInheritedAttribute($throwable::class, WithLogLevel::class)) {\n            return $withLogLevel->level;\n        }\n\n        if (!$throwable instanceof HttpExceptionInterface || $throwable->getStatusCode() >= 500) {\n            return LogLevel::CRITICAL;\n        }\n\n        return LogLevel::ERROR;\n    }\n\n    private function resolveLogChannel(\\Throwable $throwable): ?string\n    {\n        foreach ($this->exceptionsMapping as $class => $config) {\n            if ($throwable instanceof $class && isset($config['log_channel'])) {\n                return $config['log_channel'];\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Clones the request for the exception.\n     */\n    protected function duplicateRequest(\\Throwable $exception, Request $request): Request\n    {\n        $attributes = [\n            '_controller' => $this->controller,\n            'exception' => $exception,\n            'logger' => DebugLoggerConfigurator::getDebugLogger($this->getLogger($this->resolveLogChannel($exception))),\n        ];\n        $request = $request->duplicate(null, null, $attributes);\n        $request->setMethod('GET');\n\n        return $request;\n    }\n\n    /**\n     * @template T\n     *\n     * @param class-string<T> $attribute\n     *\n     * @return T|null\n     */\n    private function getInheritedAttribute(string $class, string $attribute): ?object\n    {\n        $class = new \\ReflectionClass($class);\n        $interfaces = [];\n        $attributeReflector = null;\n        $parentInterfaces = [];\n        $ownInterfaces = [];\n\n        do {\n            if ($attributes = $class->getAttributes($attribute, \\ReflectionAttribute::IS_INSTANCEOF)) {\n                $attributeReflector = $attributes[0];\n                $parentInterfaces = class_implements($class->name);\n                break;\n            }\n\n            $interfaces[] = class_implements($class->name);\n        } while ($class = $class->getParentClass());\n\n        while ($interfaces) {\n            $ownInterfaces = array_diff_key(array_pop($interfaces), $parentInterfaces);\n            $parentInterfaces += $ownInterfaces;\n\n            foreach ($ownInterfaces as $interface) {\n                $class = new \\ReflectionClass($interface);\n\n                if ($attributes = $class->getAttributes($attribute, \\ReflectionAttribute::IS_INSTANCEOF)) {\n                    $attributeReflector = $attributes[0];\n                }\n            }\n        }\n\n        return $attributeReflector?->newInstance();\n    }\n\n    private function getLogger(?string $logChannel): ?LoggerInterface\n    {\n        return $logChannel ? $this->loggers[$logChannel] ?? $this->logger : $this->logger;\n    }\n}\n"
  },
  {
    "path": "EventListener/FragmentListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\UriSigner;\nuse Symfony\\Component\\HttpKernel\\Event\\RequestEvent;\nuse Symfony\\Component\\HttpKernel\\Exception\\AccessDeniedHttpException;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\n\n/**\n * Handles content fragments represented by special URIs.\n *\n * All URL paths starting with /_fragment are handled as\n * content fragments by this listener.\n *\n * Throws an AccessDeniedHttpException exception if the request\n * is not signed or if it is not an internal sub-request.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @final\n */\nclass FragmentListener implements EventSubscriberInterface\n{\n    /**\n     * @param string $fragmentPath The path that triggers this listener\n     */\n    public function __construct(\n        private UriSigner $signer,\n        private string $fragmentPath = '/_fragment',\n    ) {\n    }\n\n    /**\n     * Fixes request attributes when the path is '/_fragment'.\n     *\n     * @throws AccessDeniedHttpException if the request does not come from a trusted IP\n     */\n    public function onKernelRequest(RequestEvent $event): void\n    {\n        $request = $event->getRequest();\n\n        if ($this->fragmentPath !== rawurldecode($request->getPathInfo())) {\n            return;\n        }\n\n        if ($request->attributes->has('_controller')) {\n            // Is a sub-request: no need to parse _path but it should still be removed from query parameters as below.\n            $request->query->remove('_path');\n\n            return;\n        }\n\n        if ($event->isMainRequest()) {\n            $this->validateRequest($request);\n        }\n\n        parse_str($request->query->get('_path', ''), $attributes);\n        $attributes['_check_controller_is_allowed'] = true;\n        $request->attributes->add($attributes);\n        $request->attributes->set('_route_params', array_replace($request->attributes->get('_route_params', []), $attributes));\n        $request->query->remove('_path');\n    }\n\n    protected function validateRequest(Request $request): void\n    {\n        // is the Request safe?\n        if (!$request->isMethodSafe()) {\n            throw new AccessDeniedHttpException();\n        }\n\n        // is the Request signed?\n        if ($this->signer->checkRequest($request)) {\n            return;\n        }\n\n        throw new AccessDeniedHttpException();\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        return [\n            KernelEvents::REQUEST => [['onKernelRequest', 48]],\n        ];\n    }\n}\n"
  },
  {
    "path": "EventListener/IsSignatureValidAttributeListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\UriSigner;\nuse Symfony\\Component\\HttpKernel\\Attribute\\IsSignatureValid;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerAttributeEvent;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\n\n/**\n * Handles the IsSignatureValid attribute.\n *\n * @author Santiago San Martin <sanmartindev@gmail.com>\n */\nclass IsSignatureValidAttributeListener implements EventSubscriberInterface\n{\n    public function __construct(\n        private readonly UriSigner $uriSigner,\n    ) {\n    }\n\n    public function onKernelControllerAttribute(ControllerAttributeEvent $event): void\n    {\n        $kernelEvent = $event->kernelEvent;\n\n        if (!$kernelEvent instanceof ControllerArgumentsEvent) {\n            return;\n        }\n\n        $this->processAttribute($event->attribute, $kernelEvent->getRequest());\n    }\n\n    /**\n     * @internal since Symfony 8.1, use onKernelControllerAttribute() instead\n     */\n    public function onKernelControllerArguments(ControllerArgumentsEvent $event): void\n    {\n        $request = $event->getRequest();\n\n        foreach ($event->getAttributes(IsSignatureValid::class) as $attribute) {\n            $this->processAttribute($attribute, $request);\n        }\n    }\n\n    private function processAttribute(IsSignatureValid $attribute, Request $request): void\n    {\n        $methods = array_map('strtoupper', $attribute->methods);\n        if ($methods && !\\in_array($request->getMethod(), $methods, true)) {\n            return;\n        }\n\n        $this->uriSigner->verify($request);\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        if (!class_exists(ControllerAttributesListener::class, false)) {\n            return [\n                KernelEvents::CONTROLLER_ARGUMENTS => ['onKernelControllerArguments', 30],\n            ];\n        }\n\n        return [\n            KernelEvents::CONTROLLER_ARGUMENTS.'.'.IsSignatureValid::class => 'onKernelControllerAttribute',\n        ];\n    }\n}\n"
  },
  {
    "path": "EventListener/LocaleAwareListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpKernel\\Event\\FinishRequestEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\RequestEvent;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\nuse Symfony\\Contracts\\Translation\\LocaleAwareInterface;\n\n/**\n * Pass the current locale to the provided services.\n *\n * @author Pierre Bobiet <pierrebobiet@gmail.com>\n */\nclass LocaleAwareListener implements EventSubscriberInterface\n{\n    /**\n     * @param iterable<mixed, LocaleAwareInterface> $localeAwareServices\n     */\n    public function __construct(\n        private iterable $localeAwareServices,\n        private RequestStack $requestStack,\n    ) {\n    }\n\n    public function onKernelRequest(RequestEvent $event): void\n    {\n        $this->setLocale($event->getRequest()->getLocale(), $event->getRequest()->getDefaultLocale());\n    }\n\n    public function onKernelFinishRequest(FinishRequestEvent $event): void\n    {\n        if (null === $parentRequest = $this->requestStack->getParentRequest()) {\n            foreach ($this->localeAwareServices as $service) {\n                $service->setLocale($event->getRequest()->getDefaultLocale());\n            }\n\n            return;\n        }\n\n        $this->setLocale($parentRequest->getLocale(), $parentRequest->getDefaultLocale());\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        return [\n            // must be registered after the Locale listener\n            KernelEvents::REQUEST => [['onKernelRequest', 15]],\n            KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', -15]],\n        ];\n    }\n\n    private function setLocale(string $locale, string $defaultLocale): void\n    {\n        foreach ($this->localeAwareServices as $service) {\n            try {\n                $service->setLocale($locale);\n            } catch (\\InvalidArgumentException) {\n                $service->setLocale($defaultLocale);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "EventListener/LocaleListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpKernel\\Event\\FinishRequestEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\KernelEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\RequestEvent;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\nuse Symfony\\Component\\Routing\\RequestContextAwareInterface;\n\n/**\n * Initializes the locale based on the current request.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @final\n */\nclass LocaleListener implements EventSubscriberInterface\n{\n    public function __construct(\n        private RequestStack $requestStack,\n        private string $defaultLocale = 'en',\n        private ?RequestContextAwareInterface $router = null,\n        private bool $useAcceptLanguageHeader = false,\n        private array $enabledLocales = [],\n    ) {\n        $this->enabledLocales = $enabledLocales ? array_values(array_unique(array_merge([$defaultLocale], array_filter($enabledLocales)))) : [];\n    }\n\n    public function setDefaultLocale(KernelEvent $event): void\n    {\n        $event->getRequest()->setDefaultLocale($this->defaultLocale);\n        $this->setRouterLocale($this->defaultLocale);\n    }\n\n    public function onKernelRequest(RequestEvent $event): void\n    {\n        $request = $event->getRequest();\n\n        $this->setLocale($request);\n        $this->setRouterLocale($request->getLocale());\n    }\n\n    public function onKernelFinishRequest(FinishRequestEvent $event): void\n    {\n        $this->setRouterLocale($this->requestStack->getParentRequest()?->getLocale() ?? $this->defaultLocale);\n    }\n\n    private function setLocale(Request $request): void\n    {\n        if ($locale = $request->attributes->get('_locale')) {\n            $request->setLocale($locale);\n        } elseif ($this->useAcceptLanguageHeader) {\n            if ($request->getLanguages() && $preferredLanguage = $request->getPreferredLanguage($this->enabledLocales)) {\n                $request->setLocale($preferredLanguage);\n            }\n            $request->attributes->set('_vary_by_language', true);\n        }\n    }\n\n    private function setRouterLocale(string $locale): void\n    {\n        $this->router?->getContext()->setParameter('_locale', $locale);\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        return [\n            KernelEvents::REQUEST => [\n                ['setDefaultLocale', 100],\n                // must be registered after the Router to have access to the _locale\n                ['onKernelRequest', 16],\n            ],\n            KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', 0]],\n        ];\n    }\n}\n"
  },
  {
    "path": "EventListener/ProfilerListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestMatcherInterface;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Session\\Session;\nuse Symfony\\Component\\HttpKernel\\Event\\ExceptionEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\TerminateEvent;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\nuse Symfony\\Component\\HttpKernel\\Profiler\\Profile;\nuse Symfony\\Component\\HttpKernel\\Profiler\\Profiler;\n\n/**\n * ProfilerListener collects data for the current request by listening to the kernel events.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @final\n */\nclass ProfilerListener implements EventSubscriberInterface\n{\n    private ?\\Throwable $exception = null;\n    /** @var \\SplObjectStorage<Request, Profile> */\n    private \\SplObjectStorage $profiles;\n    /** @var \\SplObjectStorage<Request, Request|null> */\n    private \\SplObjectStorage $parents;\n\n    /**\n     * @param bool $onlyException    True if the profiler only collects data when an exception occurs, false otherwise\n     * @param bool $onlyMainRequests True if the profiler only collects data when the request is the main request, false otherwise\n     */\n    public function __construct(\n        private Profiler $profiler,\n        private RequestStack $requestStack,\n        private ?RequestMatcherInterface $matcher = null,\n        private bool $onlyException = false,\n        private bool $onlyMainRequests = false,\n        private ?string $collectParameter = null,\n    ) {\n        $this->profiles = new \\SplObjectStorage();\n        $this->parents = new \\SplObjectStorage();\n    }\n\n    /**\n     * Handles the onKernelException event.\n     */\n    public function onKernelException(ExceptionEvent $event): void\n    {\n        if ($this->onlyMainRequests && !$event->isMainRequest()) {\n            return;\n        }\n\n        $this->exception = $event->getThrowable();\n    }\n\n    /**\n     * Handles the onKernelResponse event.\n     */\n    public function onKernelResponse(ResponseEvent $event): void\n    {\n        if ($this->onlyMainRequests && !$event->isMainRequest()) {\n            return;\n        }\n\n        if ($this->onlyException && null === $this->exception) {\n            return;\n        }\n\n        $request = $event->getRequest();\n        if (null !== $this->collectParameter && null !== $collectParameterValue = $request->attributes->get($this->collectParameter) ?? $request->query->get($this->collectParameter) ?? $request->request->get($this->collectParameter)) {\n            filter_var($collectParameterValue, \\FILTER_VALIDATE_BOOL) ? $this->profiler->enable() : $this->profiler->disable();\n        }\n\n        $exception = $this->exception;\n        $this->exception = null;\n\n        if (null !== $this->matcher && !$this->matcher->matches($request)) {\n            return;\n        }\n\n        $session = !$request->attributes->getBoolean('_stateless') && $request->hasPreviousSession() ? $request->getSession() : null;\n\n        if ($session instanceof Session) {\n            $usageIndexValue = $usageIndexReference = &$session->getUsageIndex();\n            $usageIndexReference = \\PHP_INT_MIN;\n        }\n\n        try {\n            if (!$profile = $this->profiler->collect($request, $event->getResponse(), $exception)) {\n                return;\n            }\n        } finally {\n            if ($session instanceof Session) {\n                $usageIndexReference = $usageIndexValue;\n            }\n        }\n\n        $this->profiles[$request] = $profile;\n\n        $this->parents[$request] = $this->requestStack->getParentRequest();\n    }\n\n    public function onKernelTerminate(TerminateEvent $event): void\n    {\n        // attach children to parents\n        foreach ($this->profiles as $request) {\n            if (null !== $parentRequest = $this->parents[$request]) {\n                if (isset($this->profiles[$parentRequest])) {\n                    $this->profiles[$parentRequest]->addChild($this->profiles[$request]);\n                }\n            }\n        }\n\n        // save profiles\n        foreach ($this->profiles as $request) {\n            $this->profiler->saveProfile($this->profiles[$request]);\n        }\n\n        $this->reset();\n    }\n\n    public function reset(): void\n    {\n        $this->profiles = new \\SplObjectStorage();\n        $this->parents = new \\SplObjectStorage();\n        $this->exception = null;\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        return [\n            KernelEvents::RESPONSE => ['onKernelResponse', -100],\n            KernelEvents::EXCEPTION => ['onKernelException', 0],\n            KernelEvents::TERMINATE => ['onKernelTerminate', -1024],\n        ];\n    }\n}\n"
  },
  {
    "path": "EventListener/ResponseListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\n\n/**\n * ResponseListener fixes the Response headers based on the Request.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @final\n */\nclass ResponseListener implements EventSubscriberInterface\n{\n    public function __construct(\n        private string $charset,\n        private bool $addContentLanguageHeader = false,\n    ) {\n    }\n\n    /**\n     * Filters the Response.\n     */\n    public function onKernelResponse(ResponseEvent $event): void\n    {\n        if (!$event->isMainRequest()) {\n            return;\n        }\n\n        $response = $event->getResponse();\n\n        if (null === $response->getCharset()) {\n            $response->setCharset($this->charset);\n        }\n\n        if ($this->addContentLanguageHeader && !$response->isInformational() && !$response->isEmpty() && !$response->headers->has('Content-Language')) {\n            $response->headers->set('Content-Language', $event->getRequest()->getLocale());\n        }\n\n        if ($event->getRequest()->attributes->get('_vary_by_language')) {\n            $response->setVary('Accept-Language', false);\n        }\n\n        $response->prepare($event->getRequest());\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        return [\n            KernelEvents::RESPONSE => 'onKernelResponse',\n        ];\n    }\n}\n"
  },
  {
    "path": "EventListener/RouterListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Event\\ExceptionEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\RequestEvent;\nuse Symfony\\Component\\HttpKernel\\Exception\\BadRequestHttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\MethodNotAllowedHttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;\nuse Symfony\\Component\\HttpKernel\\Kernel;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\nuse Symfony\\Component\\Routing\\Exception\\MethodNotAllowedException;\nuse Symfony\\Component\\Routing\\Exception\\NoConfigurationException;\nuse Symfony\\Component\\Routing\\Exception\\ResourceNotFoundException;\nuse Symfony\\Component\\Routing\\Matcher\\RequestMatcherInterface;\nuse Symfony\\Component\\Routing\\Matcher\\UrlMatcherInterface;\nuse Symfony\\Component\\Routing\\RequestContext;\nuse Symfony\\Component\\Routing\\RequestContextAwareInterface;\n\n/**\n * Initializes the context from the request and sets request attributes based on a matching route.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n * @author Yonel Ceruto <yonelceruto@gmail.com>\n *\n * @final\n */\nclass RouterListener implements EventSubscriberInterface\n{\n    private RequestContext $context;\n\n    /**\n     * @param RequestContext|null $context The RequestContext (can be null when $matcher implements RequestContextAwareInterface)\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function __construct(\n        private UrlMatcherInterface|RequestMatcherInterface $matcher,\n        private RequestStack $requestStack,\n        ?RequestContext $context = null,\n        private ?LoggerInterface $logger = null,\n        private ?string $projectDir = null,\n        private bool $debug = true,\n    ) {\n        if (null === $context && !$matcher instanceof RequestContextAwareInterface) {\n            throw new \\InvalidArgumentException('You must either pass a RequestContext or the matcher must implement RequestContextAwareInterface.');\n        }\n\n        $this->context = $context ?? $matcher->getContext();\n    }\n\n    private function setCurrentRequest(?Request $request): void\n    {\n        if (null !== $request) {\n            try {\n                $this->context->fromRequest($request);\n            } catch (\\UnexpectedValueException $e) {\n                throw new BadRequestHttpException($e->getMessage(), $e, $e->getCode());\n            }\n        }\n    }\n\n    /**\n     * After a sub-request is done, we need to reset the routing context to the parent request so that the URL generator\n     * operates on the correct context again.\n     */\n    public function onKernelFinishRequest(): void\n    {\n        $this->setCurrentRequest($this->requestStack->getParentRequest());\n    }\n\n    public function onKernelRequest(RequestEvent $event): void\n    {\n        $request = $event->getRequest();\n\n        $this->setCurrentRequest($request);\n\n        if ($request->attributes->has('_controller')) {\n            // routing is already done\n            return;\n        }\n\n        // add attributes based on the request (routing)\n        try {\n            // matching a request is more powerful than matching a URL path + context, so try that first\n            if ($this->matcher instanceof RequestMatcherInterface) {\n                $parameters = $this->matcher->matchRequest($request);\n            } else {\n                $parameters = $this->matcher->match($request->getPathInfo());\n            }\n\n            $this->logger?->info('Matched route \"{route}\".', [\n                'route' => $parameters['_route'] ?? 'n/a',\n                'route_parameters' => $parameters,\n                'request_uri' => $request->getUri(),\n                'method' => $request->getMethod(),\n            ]);\n\n            $attributes = $parameters;\n            if ($mapping = $parameters['_route_mapping'] ?? false) {\n                unset($parameters['_route_mapping']);\n                $mappedAttributes = [];\n                $attributes = [];\n\n                foreach ($parameters as $parameter => $value) {\n                    if (!isset($mapping[$parameter])) {\n                        $attribute = $parameter;\n                    } elseif (\\is_array($mapping[$parameter])) {\n                        [$attribute, $parameter] = $mapping[$parameter];\n                        $mappedAttributes[$attribute] = '';\n                    } else {\n                        $attribute = $mapping[$parameter];\n                    }\n\n                    if (!isset($mappedAttributes[$attribute])) {\n                        $attributes[$attribute] = $value;\n                        $mappedAttributes[$attribute] = $parameter;\n                    } elseif ('' !== $mappedAttributes[$attribute]) {\n                        $attributes[$attribute] = [\n                            $mappedAttributes[$attribute] => $attributes[$attribute],\n                            $parameter => $value,\n                        ];\n                        $mappedAttributes[$attribute] = '';\n                    } else {\n                        $attributes[$attribute][$parameter] = $value;\n                    }\n                }\n\n                $attributes['_route_mapping'] = $mapping;\n            }\n\n            $request->attributes->add($attributes);\n            unset($parameters['_route'], $parameters['_controller']);\n            $request->attributes->set('_route_params', $parameters);\n        } catch (ResourceNotFoundException $e) {\n            $message = \\sprintf('No route found for \"%s %s\"', $request->getMethod(), $request->getUriForPath($request->getPathInfo()));\n\n            if ($referer = $request->headers->get('referer')) {\n                $message .= \\sprintf(' (from \"%s\")', $referer);\n            }\n\n            throw new NotFoundHttpException($message, $e);\n        } catch (MethodNotAllowedException $e) {\n            $message = \\sprintf('No route found for \"%s %s\": Method Not Allowed (Allow: %s)', $request->getMethod(), $request->getUriForPath($request->getPathInfo()), implode(', ', $e->getAllowedMethods()));\n\n            throw new MethodNotAllowedHttpException($e->getAllowedMethods(), $message, $e);\n        }\n    }\n\n    public function onKernelException(ExceptionEvent $event): void\n    {\n        if (!$this->debug || !($e = $event->getThrowable()) instanceof NotFoundHttpException) {\n            return;\n        }\n\n        if ($e->getPrevious() instanceof NoConfigurationException) {\n            $event->setResponse($this->createWelcomeResponse());\n        }\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        return [\n            KernelEvents::REQUEST => [['onKernelRequest', 32]],\n            KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', 0]],\n            KernelEvents::EXCEPTION => ['onKernelException', -64],\n        ];\n    }\n\n    private function createWelcomeResponse(): Response\n    {\n        $version = Kernel::VERSION;\n        $projectDir = realpath((string) $this->projectDir).\\DIRECTORY_SEPARATOR;\n        $docVersion = substr(Kernel::VERSION, 0, 3);\n\n        ob_start();\n        include \\dirname(__DIR__).'/Resources/welcome.html.php';\n\n        return new Response(ob_get_clean(), Response::HTTP_NOT_FOUND);\n    }\n}\n"
  },
  {
    "path": "EventListener/SerializeControllerResultAttributeListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Attribute\\Serialize;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerAttributeEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ViewEvent;\nuse Symfony\\Component\\HttpKernel\\Exception\\UnsupportedMediaTypeHttpException;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\nuse Symfony\\Component\\Serializer\\Exception\\UnsupportedFormatException;\nuse Symfony\\Component\\Serializer\\SerializerInterface;\n\n/**\n * @author Konstantin Myakshin <molodchick@gmail.com>\n */\nfinal class SerializeControllerResultAttributeListener implements EventSubscriberInterface\n{\n    public function __construct(private readonly ?SerializerInterface $serializer)\n    {\n    }\n\n    /**\n     * @param ControllerAttributeEvent<Serialize> $event\n     */\n    public function onView(ControllerAttributeEvent $event): void\n    {\n        $kernelEvent = $event->kernelEvent;\n\n        if (!$kernelEvent instanceof ViewEvent) {\n            return;\n        }\n\n        if (!$this->serializer) {\n            throw new \\LogicException(\\sprintf('The \"symfony/serializer\" component is required to use the \"#[%s]\" attribute. Try running \"composer require symfony/serializer\".', Serialize::class));\n        }\n\n        $request = $kernelEvent->getRequest();\n        $controllerResult = $kernelEvent->getControllerResult();\n        $format = $request->getRequestFormat('json');\n\n        try {\n            $data = $this->serializer->serialize($controllerResult, $format, $event->attribute->context);\n        } catch (UnsupportedFormatException $exception) {\n            throw new UnsupportedMediaTypeHttpException(\\sprintf('Unsupported format \"%s\".', $format), $exception->getPrevious());\n        }\n\n        $headers = $this->mergeHeaders($event->attribute, $request, $format);\n        $response = new Response($data, $event->attribute->code, $headers);\n\n        $kernelEvent->setResponse($response);\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        return [\n            KernelEvents::VIEW.'.'.Serialize::class => 'onView',\n        ];\n    }\n\n    /**\n     * @return array<string, scalar>\n     */\n    private function mergeHeaders(Serialize $attribute, Request $request, string $format): array\n    {\n        $headers = array_combine(\n            array_map('strtolower', array_keys($attribute->headers)),\n            array_values($attribute->headers),\n        );\n\n        if (!isset($headers['content-type'])) {\n            $headers['content-type'] = $request->getMimeType($format);\n        }\n\n        return $headers;\n    }\n}\n"
  },
  {
    "path": "EventListener/SessionListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Psr\\Container\\ContainerInterface;\nuse Symfony\\Component\\HttpFoundation\\Session\\SessionInterface;\n\n/**\n * Sets the session in the request.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @final\n */\nclass SessionListener extends AbstractSessionListener\n{\n    public function __construct(\n        private ?ContainerInterface $container = null,\n        bool $debug = false,\n        array $sessionOptions = [],\n    ) {\n        parent::__construct($container, $debug, $sessionOptions);\n    }\n\n    protected function getSession(): ?SessionInterface\n    {\n        if ($this->container->has('session_factory')) {\n            return $this->container->get('session_factory')->createSession();\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "EventListener/SurrogateListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\SurrogateInterface;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\n\n/**\n * SurrogateListener adds a Surrogate-Control HTTP header when the Response needs to be parsed for Surrogates.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @final\n */\nclass SurrogateListener implements EventSubscriberInterface\n{\n    public function __construct(\n        private ?SurrogateInterface $surrogate = null,\n    ) {\n    }\n\n    /**\n     * Filters the Response.\n     */\n    public function onKernelResponse(ResponseEvent $event): void\n    {\n        if (!$event->isMainRequest()) {\n            return;\n        }\n\n        $kernel = $event->getKernel();\n        $surrogate = $this->surrogate;\n        if ($kernel instanceof HttpCache) {\n            $surrogate = $kernel->getSurrogate();\n            if (null !== $this->surrogate && $this->surrogate->getName() !== $surrogate->getName()) {\n                $surrogate = $this->surrogate;\n            }\n        }\n\n        if (null === $surrogate) {\n            return;\n        }\n\n        $surrogate->addSurrogateControl($event->getResponse());\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        return [\n            KernelEvents::RESPONSE => 'onKernelResponse',\n        ];\n    }\n}\n"
  },
  {
    "path": "EventListener/ValidateRequestListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\EventListener;\n\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpKernel\\Event\\RequestEvent;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\n\n/**\n * Validates Requests.\n *\n * @author Magnus Nordlander <magnus@fervo.se>\n *\n * @final\n */\nclass ValidateRequestListener implements EventSubscriberInterface\n{\n    /**\n     * Performs the validation.\n     */\n    public function onKernelRequest(RequestEvent $event): void\n    {\n        if (!$event->isMainRequest()) {\n            return;\n        }\n        $request = $event->getRequest();\n\n        if ($request::getTrustedProxies()) {\n            $request->getClientIps();\n        }\n\n        $request->getHost();\n    }\n\n    public static function getSubscribedEvents(): array\n    {\n        return [\n            KernelEvents::REQUEST => [\n                ['onKernelRequest', 256],\n            ],\n        ];\n    }\n}\n"
  },
  {
    "path": "Exception/AccessDeniedHttpException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n * @author Christophe Coevoet <stof@notk.org>\n */\nclass AccessDeniedHttpException extends HttpException\n{\n    public function __construct(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = [])\n    {\n        parent::__construct(403, $message, $previous, $headers, $code);\n    }\n}\n"
  },
  {
    "path": "Exception/BadRequestHttpException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * @author Ben Ramsey <ben@benramsey.com>\n */\nclass BadRequestHttpException extends HttpException\n{\n    public function __construct(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = [])\n    {\n        parent::__construct(400, $message, $previous, $headers, $code);\n    }\n}\n"
  },
  {
    "path": "Exception/ConflictHttpException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * @author Ben Ramsey <ben@benramsey.com>\n */\nclass ConflictHttpException extends HttpException\n{\n    public function __construct(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = [])\n    {\n        parent::__construct(409, $message, $previous, $headers, $code);\n    }\n}\n"
  },
  {
    "path": "Exception/ControllerDoesNotReturnResponseException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * @author Grégoire Pineau <lyrixx@lyrixx.info>\n */\nclass ControllerDoesNotReturnResponseException extends \\LogicException\n{\n    public function __construct(string $message, callable $controller, string $file, int $line)\n    {\n        parent::__construct($message);\n\n        if (!$controllerDefinition = $this->parseControllerDefinition($controller)) {\n            return;\n        }\n\n        $this->file = $controllerDefinition['file'];\n        $this->line = $controllerDefinition['line'];\n        $r = new \\ReflectionProperty(\\Exception::class, 'trace');\n        $r->setValue($this, array_merge([\n            [\n                'line' => $line,\n                'file' => $file,\n            ],\n        ], $this->getTrace()));\n    }\n\n    private function parseControllerDefinition(callable $controller): ?array\n    {\n        if (\\is_string($controller) && str_contains($controller, '::')) {\n            $controller = explode('::', $controller);\n        }\n\n        if (\\is_array($controller)) {\n            try {\n                $r = new \\ReflectionMethod($controller[0], $controller[1]);\n\n                return [\n                    'file' => $r->getFileName(),\n                    'line' => $r->getEndLine(),\n                ];\n            } catch (\\ReflectionException) {\n                return null;\n            }\n        }\n\n        if ($controller instanceof \\Closure) {\n            $r = new \\ReflectionFunction($controller);\n\n            return [\n                'file' => $r->getFileName(),\n                'line' => $r->getEndLine(),\n            ];\n        }\n\n        if (\\is_object($controller)) {\n            $r = new \\ReflectionClass($controller);\n\n            try {\n                $line = $r->getMethod('__invoke')->getEndLine();\n            } catch (\\ReflectionException) {\n                $line = $r->getEndLine();\n            }\n\n            return [\n                'file' => $r->getFileName(),\n                'line' => $line,\n            ];\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "Exception/GoneHttpException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * @author Ben Ramsey <ben@benramsey.com>\n */\nclass GoneHttpException extends HttpException\n{\n    public function __construct(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = [])\n    {\n        parent::__construct(410, $message, $previous, $headers, $code);\n    }\n}\n"
  },
  {
    "path": "Exception/HttpException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * HttpException.\n *\n * @author Kris Wallsmith <kris@symfony.com>\n */\nclass HttpException extends \\RuntimeException implements HttpExceptionInterface\n{\n    public function __construct(\n        private int $statusCode,\n        string $message = '',\n        ?\\Throwable $previous = null,\n        private array $headers = [],\n        int $code = 0,\n    ) {\n        parent::__construct($message, $code, $previous);\n    }\n\n    public static function fromStatusCode(int $statusCode, string $message = '', ?\\Throwable $previous = null, array $headers = [], int $code = 0): self\n    {\n        return match ($statusCode) {\n            400 => new BadRequestHttpException($message, $previous, $code, $headers),\n            403 => new AccessDeniedHttpException($message, $previous, $code, $headers),\n            404 => new NotFoundHttpException($message, $previous, $code, $headers),\n            406 => new NotAcceptableHttpException($message, $previous, $code, $headers),\n            409 => new ConflictHttpException($message, $previous, $code, $headers),\n            410 => new GoneHttpException($message, $previous, $code, $headers),\n            411 => new LengthRequiredHttpException($message, $previous, $code, $headers),\n            412 => new PreconditionFailedHttpException($message, $previous, $code, $headers),\n            423 => new LockedHttpException($message, $previous, $code, $headers),\n            415 => new UnsupportedMediaTypeHttpException($message, $previous, $code, $headers),\n            422 => new UnprocessableEntityHttpException($message, $previous, $code, $headers),\n            428 => new PreconditionRequiredHttpException($message, $previous, $code, $headers),\n            429 => new TooManyRequestsHttpException(null, $message, $previous, $code, $headers),\n            503 => new ServiceUnavailableHttpException(null, $message, $previous, $code, $headers),\n            default => new static($statusCode, $message, $previous, $headers, $code),\n        };\n    }\n\n    public function getStatusCode(): int\n    {\n        return $this->statusCode;\n    }\n\n    public function getHeaders(): array\n    {\n        return $this->headers;\n    }\n\n    public function setHeaders(array $headers): void\n    {\n        $this->headers = $headers;\n    }\n}\n"
  },
  {
    "path": "Exception/HttpExceptionInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * Interface for HTTP error exceptions.\n *\n * @author Kris Wallsmith <kris@symfony.com>\n */\ninterface HttpExceptionInterface extends \\Throwable\n{\n    /**\n     * Returns the status code.\n     */\n    public function getStatusCode(): int;\n\n    /**\n     * Returns response headers.\n     */\n    public function getHeaders(): array;\n}\n"
  },
  {
    "path": "Exception/InvalidMetadataException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\nclass InvalidMetadataException extends \\LogicException\n{\n}\n"
  },
  {
    "path": "Exception/LengthRequiredHttpException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * @author Ben Ramsey <ben@benramsey.com>\n */\nclass LengthRequiredHttpException extends HttpException\n{\n    public function __construct(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = [])\n    {\n        parent::__construct(411, $message, $previous, $headers, $code);\n    }\n}\n"
  },
  {
    "path": "Exception/LockedHttpException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * @author Peter Dietrich <xosofox@gmail.com>\n */\nclass LockedHttpException extends HttpException\n{\n    public function __construct(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = [])\n    {\n        parent::__construct(423, $message, $previous, $headers, $code);\n    }\n}\n"
  },
  {
    "path": "Exception/MethodNotAllowedHttpException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * @author Kris Wallsmith <kris@symfony.com>\n */\nclass MethodNotAllowedHttpException extends HttpException\n{\n    /**\n     * @param string[] $allow An array of allowed methods\n     */\n    public function __construct(array $allow, string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = [])\n    {\n        $headers['Allow'] = strtoupper(implode(', ', $allow));\n\n        parent::__construct(405, $message, $previous, $headers, $code);\n    }\n}\n"
  },
  {
    "path": "Exception/NearMissValueResolverException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * Lets value resolvers tell when an argument could be under their watch but failed to be resolved.\n *\n * Throwing this exception inside `ValueResolverInterface::resolve` does not interrupt the value resolvers chain.\n */\nclass NearMissValueResolverException extends \\RuntimeException\n{\n}\n"
  },
  {
    "path": "Exception/NotAcceptableHttpException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * @author Ben Ramsey <ben@benramsey.com>\n */\nclass NotAcceptableHttpException extends HttpException\n{\n    public function __construct(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = [])\n    {\n        parent::__construct(406, $message, $previous, $headers, $code);\n    }\n}\n"
  },
  {
    "path": "Exception/NotFoundHttpException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass NotFoundHttpException extends HttpException\n{\n    public function __construct(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = [])\n    {\n        parent::__construct(404, $message, $previous, $headers, $code);\n    }\n}\n"
  },
  {
    "path": "Exception/PreconditionFailedHttpException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * @author Ben Ramsey <ben@benramsey.com>\n */\nclass PreconditionFailedHttpException extends HttpException\n{\n    public function __construct(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = [])\n    {\n        parent::__construct(412, $message, $previous, $headers, $code);\n    }\n}\n"
  },
  {
    "path": "Exception/PreconditionRequiredHttpException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * @author Ben Ramsey <ben@benramsey.com>\n *\n * @see http://tools.ietf.org/html/rfc6585\n */\nclass PreconditionRequiredHttpException extends HttpException\n{\n    public function __construct(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = [])\n    {\n        parent::__construct(428, $message, $previous, $headers, $code);\n    }\n}\n"
  },
  {
    "path": "Exception/ResolverNotFoundException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\nclass ResolverNotFoundException extends \\RuntimeException\n{\n    /**\n     * @param string[] $alternatives\n     */\n    public function __construct(string $name, array $alternatives = [])\n    {\n        $msg = \\sprintf('You have requested a non-existent resolver \"%s\".', $name);\n        if ($alternatives) {\n            if (1 === \\count($alternatives)) {\n                $msg .= ' Did you mean this: \"';\n            } else {\n                $msg .= ' Did you mean one of these: \"';\n            }\n            $msg .= implode('\", \"', $alternatives).'\"?';\n        }\n\n        parent::__construct($msg);\n    }\n}\n"
  },
  {
    "path": "Exception/ServiceUnavailableHttpException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * @author Ben Ramsey <ben@benramsey.com>\n */\nclass ServiceUnavailableHttpException extends HttpException\n{\n    /**\n     * @param int|string|null $retryAfter The number of seconds or HTTP-date after which the request may be retried\n     */\n    public function __construct(int|string|null $retryAfter = null, string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = [])\n    {\n        if ($retryAfter) {\n            $headers['Retry-After'] = $retryAfter;\n        }\n\n        parent::__construct(503, $message, $previous, $headers, $code);\n    }\n}\n"
  },
  {
    "path": "Exception/TooManyRequestsHttpException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * @author Ben Ramsey <ben@benramsey.com>\n *\n * @see http://tools.ietf.org/html/rfc6585\n */\nclass TooManyRequestsHttpException extends HttpException\n{\n    /**\n     * @param int|string|null $retryAfter The number of seconds or HTTP-date after which the request may be retried\n     */\n    public function __construct(int|string|null $retryAfter = null, string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = [])\n    {\n        if ($retryAfter) {\n            $headers['Retry-After'] = $retryAfter;\n        }\n\n        parent::__construct(429, $message, $previous, $headers, $code);\n    }\n}\n"
  },
  {
    "path": "Exception/UnauthorizedHttpException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * @author Ben Ramsey <ben@benramsey.com>\n */\nclass UnauthorizedHttpException extends HttpException\n{\n    /**\n     * @param string $challenge WWW-Authenticate challenge string\n     */\n    public function __construct(string $challenge, string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = [])\n    {\n        $headers['WWW-Authenticate'] = $challenge;\n\n        parent::__construct(401, $message, $previous, $headers, $code);\n    }\n}\n"
  },
  {
    "path": "Exception/UnexpectedSessionUsageException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * @author Mathias Arlaud <mathias.arlaud@gmail.com>\n */\nclass UnexpectedSessionUsageException extends \\LogicException\n{\n}\n"
  },
  {
    "path": "Exception/UnprocessableEntityHttpException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * @author Steve Hutchins <hutchinsteve@gmail.com>\n */\nclass UnprocessableEntityHttpException extends HttpException\n{\n    public function __construct(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = [])\n    {\n        parent::__construct(422, $message, $previous, $headers, $code);\n    }\n}\n"
  },
  {
    "path": "Exception/UnsupportedMediaTypeHttpException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Exception;\n\n/**\n * @author Ben Ramsey <ben@benramsey.com>\n */\nclass UnsupportedMediaTypeHttpException extends HttpException\n{\n    public function __construct(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = [])\n    {\n        parent::__construct(415, $message, $previous, $headers, $code);\n    }\n}\n"
  },
  {
    "path": "Fragment/AbstractSurrogateFragmentRenderer.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Fragment;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpFoundation\\UriSigner;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerReference;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\SurrogateInterface;\n\n/**\n * Implements Surrogate rendering strategy.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nabstract class AbstractSurrogateFragmentRenderer extends RoutableFragmentRenderer\n{\n    /**\n     * The \"fallback\" strategy when surrogate is not available should always be an\n     * instance of InlineFragmentRenderer.\n     *\n     * @param FragmentRendererInterface $inlineStrategy The inline strategy to use when the surrogate is not supported\n     */\n    public function __construct(\n        private ?SurrogateInterface $surrogate,\n        private FragmentRendererInterface $inlineStrategy,\n        private ?UriSigner $signer = null,\n    ) {\n    }\n\n    /**\n     * Note that if the current Request has no surrogate capability, this method\n     * falls back to use the inline rendering strategy.\n     *\n     * Additional available options:\n     *\n     *  * alt: an alternative URI to render in case of an error\n     *  * comment: a comment to add when returning the surrogate tag\n     *  * absolute_uri: whether to generate an absolute URI or not. Default is false\n     *\n     * Note, that not all surrogate strategies support all options. For now\n     * 'alt' and 'comment' are only supported by ESI.\n     *\n     * @see Symfony\\Component\\HttpKernel\\HttpCache\\SurrogateInterface\n     */\n    public function render(string|ControllerReference $uri, Request $request, array $options = []): Response\n    {\n        if (!$this->surrogate || !$this->surrogate->hasSurrogateCapability($request)) {\n            $request->attributes->set('_check_controller_is_allowed', true);\n\n            if ($uri instanceof ControllerReference && $this->containsNonScalars($uri->attributes)) {\n                throw new \\InvalidArgumentException('Passing non-scalar values as part of URI attributes to the ESI and SSI rendering strategies is not supported. Use a different rendering strategy or pass scalar values.');\n            }\n\n            return $this->inlineStrategy->render($uri, $request, $options);\n        }\n\n        $absolute = $options['absolute_uri'] ?? false;\n\n        if ($uri instanceof ControllerReference) {\n            $uri = $this->generateSignedFragmentUri($uri, $request, $absolute);\n        }\n\n        $alt = $options['alt'] ?? null;\n        if ($alt instanceof ControllerReference) {\n            $alt = $this->generateSignedFragmentUri($alt, $request, $absolute);\n        }\n\n        $tag = $this->surrogate->renderIncludeTag($uri, $alt, $options['ignore_errors'] ?? false, $options['comment'] ?? '');\n\n        return new Response($tag);\n    }\n\n    private function generateSignedFragmentUri(ControllerReference $uri, Request $request, bool $absolute): string\n    {\n        return (new FragmentUriGenerator($this->fragmentPath, $this->signer))->generate($uri, $request, $absolute);\n    }\n\n    private function containsNonScalars(array $values): bool\n    {\n        foreach ($values as $value) {\n            if (\\is_scalar($value) || null === $value) {\n                continue;\n            }\n\n            if (!\\is_array($value) || $this->containsNonScalars($value)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "Fragment/EsiFragmentRenderer.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Fragment;\n\n/**\n * Implements the ESI rendering strategy.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass EsiFragmentRenderer extends AbstractSurrogateFragmentRenderer\n{\n    public function getName(): string\n    {\n        return 'esi';\n    }\n}\n"
  },
  {
    "path": "Fragment/FragmentHandler.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Fragment;\n\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpFoundation\\StreamedResponse;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerReference;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\n\n/**\n * Renders a URI that represents a resource fragment.\n *\n * This class handles the rendering of resource fragments that are included into\n * a main resource. The handling of the rendering is managed by specialized renderers.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @see FragmentRendererInterface\n */\nclass FragmentHandler\n{\n    /** @var array<string, FragmentRendererInterface> */\n    private array $renderers = [];\n\n    /**\n     * @param FragmentRendererInterface[] $renderers An array of FragmentRendererInterface instances\n     * @param bool                        $debug     Whether the debug mode is enabled or not\n     */\n    public function __construct(\n        private RequestStack $requestStack,\n        array $renderers = [],\n        private bool $debug = false,\n    ) {\n        foreach ($renderers as $renderer) {\n            $this->addRenderer($renderer);\n        }\n    }\n\n    /**\n     * Adds a renderer.\n     */\n    public function addRenderer(FragmentRendererInterface $renderer): void\n    {\n        $this->renderers[$renderer->getName()] = $renderer;\n    }\n\n    /**\n     * Renders a URI and returns the Response content.\n     *\n     * Available options:\n     *\n     *  * ignore_errors: true to return an empty string in case of an error\n     *\n     * @throws \\InvalidArgumentException when the renderer does not exist\n     * @throws \\LogicException           when no main request is being handled\n     */\n    public function render(string|ControllerReference $uri, string $renderer = 'inline', array $options = []): ?string\n    {\n        if (!isset($options['ignore_errors'])) {\n            $options['ignore_errors'] = !$this->debug;\n        }\n\n        if (!isset($this->renderers[$renderer])) {\n            throw new \\InvalidArgumentException(\\sprintf('The \"%s\" renderer does not exist.', $renderer));\n        }\n\n        if (!$request = $this->requestStack->getCurrentRequest()) {\n            throw new \\LogicException('Rendering a fragment can only be done when handling a Request.');\n        }\n\n        return $this->deliver($this->renderers[$renderer]->render($uri, $request, $options));\n    }\n\n    /**\n     * Delivers the Response as a string.\n     *\n     * When the Response is a StreamedResponse, the content is streamed immediately\n     * instead of being returned.\n     *\n     * @return string|null The Response content or null when the Response is streamed\n     *\n     * @throws \\RuntimeException when the Response is not successful\n     */\n    protected function deliver(Response $response): ?string\n    {\n        if (!$response->isSuccessful()) {\n            $responseStatusCode = $response->getStatusCode();\n            throw new \\RuntimeException(\\sprintf('Error when rendering \"%s\" (Status code is %d).', $this->requestStack->getCurrentRequest()->getUri(), $responseStatusCode), 0, new HttpException($responseStatusCode));\n        }\n\n        if (!$response instanceof StreamedResponse) {\n            return $response->getContent();\n        }\n\n        $response->sendContent();\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "Fragment/FragmentRendererInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Fragment;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerReference;\n\n/**\n * Interface implemented by all rendering strategies.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface FragmentRendererInterface\n{\n    /**\n     * Renders a URI and returns the Response content.\n     */\n    public function render(string|ControllerReference $uri, Request $request, array $options = []): Response;\n\n    /**\n     * Gets the name of the strategy.\n     */\n    public function getName(): string;\n}\n"
  },
  {
    "path": "Fragment/FragmentUriGenerator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Fragment;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\UriSigner;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerReference;\n\n/**\n * Generates a fragment URI.\n *\n * @author Kévin Dunglas <kevin@dunglas.fr>\n * @author Fabien Potencier <fabien@symfony.com>\n */\nfinal class FragmentUriGenerator implements FragmentUriGeneratorInterface\n{\n    public function __construct(\n        private string $fragmentPath,\n        private ?UriSigner $signer = null,\n        private ?RequestStack $requestStack = null,\n    ) {\n    }\n\n    public function generate(ControllerReference $controller, ?Request $request = null, bool $absolute = false, bool $strict = true, bool $sign = true): string\n    {\n        if (null === $request && (null === $this->requestStack || null === $request = $this->requestStack->getCurrentRequest())) {\n            throw new \\LogicException('Generating a fragment URL can only be done when handling a Request.');\n        }\n\n        if ($sign && null === $this->signer) {\n            throw new \\LogicException('You must use a URI when using the ESI rendering strategy or set a URL signer.');\n        }\n\n        if ($strict) {\n            $this->checkNonScalar($controller->attributes);\n        }\n\n        // We need to forward the current _format and _locale values as we don't have\n        // a proper routing pattern to do the job for us.\n        // This makes things inconsistent if you switch from rendering a controller\n        // to rendering a route if the route pattern does not contain the special\n        // _format and _locale placeholders.\n        if (!isset($controller->attributes['_format'])) {\n            $controller->attributes['_format'] = $request->getRequestFormat();\n        }\n        if (!isset($controller->attributes['_locale'])) {\n            $controller->attributes['_locale'] = $request->getLocale();\n        }\n\n        $controller->attributes['_controller'] = $controller->controller;\n        $controller->query['_path'] = http_build_query($controller->attributes, '', '&');\n        $path = $this->fragmentPath.'?'.http_build_query($controller->query, '', '&');\n\n        // we need to sign the absolute URI, but want to return the path only.\n        $fragmentUri = $sign || $absolute ? $request->getUriForPath($path) : $request->getBaseUrl().$path;\n\n        if (!$sign) {\n            return $fragmentUri;\n        }\n\n        $fragmentUri = $this->signer->sign($fragmentUri);\n\n        return $absolute ? $fragmentUri : substr($fragmentUri, \\strlen($request->getSchemeAndHttpHost()));\n    }\n\n    private function checkNonScalar(array $values): void\n    {\n        foreach ($values as $key => $value) {\n            if (\\is_array($value)) {\n                $this->checkNonScalar($value);\n            } elseif (!\\is_scalar($value) && null !== $value) {\n                throw new \\LogicException(\\sprintf('Controller attributes cannot contain non-scalar/non-null values (value for key \"%s\" is not a scalar or null).', $key));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Fragment/FragmentUriGeneratorInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Fragment;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerReference;\n\n/**\n * Interface implemented by rendering strategies able to generate a URL for a fragment.\n *\n * @author Kévin Dunglas <kevin@dunglas.fr>\n */\ninterface FragmentUriGeneratorInterface\n{\n    /**\n     * Generates a fragment URI for a given controller.\n     *\n     * @param bool $absolute Whether to generate an absolute URL or not\n     * @param bool $strict   Whether to allow non-scalar attributes or not\n     * @param bool $sign     Whether to sign the URL or not\n     */\n    public function generate(ControllerReference $controller, ?Request $request = null, bool $absolute = false, bool $strict = true, bool $sign = true): string;\n}\n"
  },
  {
    "path": "Fragment/HIncludeFragmentRenderer.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Fragment;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpFoundation\\UriSigner;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerReference;\nuse Twig\\Environment;\n\n/**\n * Implements the Hinclude rendering strategy.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass HIncludeFragmentRenderer extends RoutableFragmentRenderer\n{\n    /**\n     * @param string|null $globalDefaultTemplate The global default content (it can be a template name or the content)\n     */\n    public function __construct(\n        private ?Environment $twig = null,\n        private ?UriSigner $signer = null,\n        private ?string $globalDefaultTemplate = null,\n        private string $charset = 'utf-8',\n    ) {\n    }\n\n    /**\n     * Checks if a templating engine has been set.\n     */\n    public function hasTemplating(): bool\n    {\n        return null !== $this->twig;\n    }\n\n    /**\n     * Additional available options:\n     *\n     *  * default:    The default content (it can be a template name or the content)\n     *  * id:         An optional hx:include tag id attribute\n     *  * attributes: An optional array of hx:include tag attributes\n     */\n    public function render(string|ControllerReference $uri, Request $request, array $options = []): Response\n    {\n        if ($uri instanceof ControllerReference) {\n            $uri = (new FragmentUriGenerator($this->fragmentPath, $this->signer))->generate($uri, $request);\n        }\n\n        // We need to replace ampersands in the URI with the encoded form in order to return valid html/xml content.\n        $uri = str_replace('&', '&amp;', $uri);\n\n        $template = $options['default'] ?? $this->globalDefaultTemplate;\n        if (null !== $this->twig && $template && $this->twig->getLoader()->exists($template)) {\n            $content = $this->twig->render($template);\n        } else {\n            $content = $template;\n        }\n\n        $attributes = isset($options['attributes']) && \\is_array($options['attributes']) ? $options['attributes'] : [];\n        if (isset($options['id']) && $options['id']) {\n            $attributes['id'] = $options['id'];\n        }\n        $renderedAttributes = '';\n        if (\\count($attributes) > 0) {\n            $flags = \\ENT_QUOTES | \\ENT_SUBSTITUTE;\n            foreach ($attributes as $attribute => $value) {\n                $renderedAttributes .= \\sprintf(\n                    ' %s=\"%s\"',\n                    htmlspecialchars($attribute, $flags, $this->charset, false),\n                    htmlspecialchars($value, $flags, $this->charset, false)\n                );\n            }\n        }\n\n        return new Response(\\sprintf('<hx:include src=\"%s\"%s>%s</hx:include>', $uri, $renderedAttributes, $content));\n    }\n\n    public function getName(): string\n    {\n        return 'hinclude';\n    }\n}\n"
  },
  {
    "path": "Fragment/InlineFragmentRenderer.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Fragment;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerReference;\nuse Symfony\\Component\\HttpKernel\\Event\\ExceptionEvent;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\SubRequestHandler;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\nuse Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface;\n\n/**\n * Implements the inline rendering strategy where the Request is rendered by the current HTTP kernel.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass InlineFragmentRenderer extends RoutableFragmentRenderer\n{\n    public function __construct(\n        private HttpKernelInterface $kernel,\n        private ?EventDispatcherInterface $dispatcher = null,\n    ) {\n    }\n\n    /**\n     * Additional available options:\n     *\n     *  * alt: an alternative URI to render in case of an error\n     */\n    public function render(string|ControllerReference $uri, Request $request, array $options = []): Response\n    {\n        $reference = null;\n        if ($uri instanceof ControllerReference) {\n            $reference = $uri;\n\n            // Remove attributes from the generated URI because if not, the Symfony\n            // routing system will use them to populate the Request attributes. We don't\n            // want that as we want to preserve objects (so we manually set Request attributes\n            // below instead)\n            $attributes = $reference->attributes;\n            $reference->attributes = [];\n\n            // The request format and locale might have been overridden by the user\n            foreach (['_format', '_locale'] as $key) {\n                if (isset($attributes[$key])) {\n                    $reference->attributes[$key] = $attributes[$key];\n                }\n            }\n\n            $uri = $this->generateFragmentUri($uri, $request, false, false);\n\n            $reference->attributes = array_merge($attributes, $reference->attributes);\n        }\n\n        $subRequest = $this->createSubRequest($uri, $request);\n\n        // override Request attributes as they can be objects (which are not supported by the generated URI)\n        if (null !== $reference) {\n            $subRequest->attributes->add($reference->attributes);\n        }\n\n        $level = ob_get_level();\n        try {\n            return SubRequestHandler::handle($this->kernel, $subRequest, HttpKernelInterface::SUB_REQUEST, false);\n        } catch (\\Exception $e) {\n            // we dispatch the exception event to trigger the logging\n            // the response that comes back is ignored\n            if (isset($options['ignore_errors']) && $options['ignore_errors'] && $this->dispatcher) {\n                $event = new ExceptionEvent($this->kernel, $request, HttpKernelInterface::SUB_REQUEST, $e);\n\n                $this->dispatcher->dispatch($event, KernelEvents::EXCEPTION);\n            }\n\n            // let's clean up the output buffers that were created by the sub-request\n            Response::closeOutputBuffers($level, false);\n\n            if (isset($options['alt'])) {\n                $alt = $options['alt'];\n                unset($options['alt']);\n\n                return $this->render($alt, $request, $options);\n            }\n\n            if (!isset($options['ignore_errors']) || !$options['ignore_errors']) {\n                throw $e;\n            }\n\n            return new Response();\n        }\n    }\n\n    protected function createSubRequest(string $uri, Request $request): Request\n    {\n        $cookies = $request->cookies->all();\n        $server = $request->server->all();\n\n        unset($server['HTTP_IF_MODIFIED_SINCE']);\n        unset($server['HTTP_IF_NONE_MATCH']);\n\n        $subRequest = Request::create($uri, 'get', [], $cookies, [], $server);\n        if ($request->headers->has('Surrogate-Capability')) {\n            $subRequest->headers->set('Surrogate-Capability', $request->headers->get('Surrogate-Capability'));\n        }\n\n        static $setSession;\n\n        $setSession ??= \\Closure::bind(static function ($subRequest, $request) { $subRequest->session = $request->session; }, null, Request::class);\n        $setSession($subRequest, $request);\n\n        if ($request->attributes->has('_format')) {\n            $subRequest->attributes->set('_format', $request->attributes->get('_format'));\n        }\n        if ($request->getDefaultLocale() !== $request->getLocale()) {\n            $subRequest->setLocale($request->getLocale());\n        }\n        if ($request->attributes->has('_stateless')) {\n            $subRequest->attributes->set('_stateless', $request->attributes->get('_stateless'));\n        }\n        if ($request->attributes->has('_check_controller_is_allowed')) {\n            $subRequest->attributes->set('_check_controller_is_allowed', $request->attributes->get('_check_controller_is_allowed'));\n        }\n\n        return $subRequest;\n    }\n\n    public function getName(): string\n    {\n        return 'inline';\n    }\n}\n"
  },
  {
    "path": "Fragment/RoutableFragmentRenderer.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Fragment;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerReference;\nuse Symfony\\Component\\HttpKernel\\EventListener\\FragmentListener;\n\n/**\n * Adds the possibility to generate a fragment URI for a given Controller.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nabstract class RoutableFragmentRenderer implements FragmentRendererInterface\n{\n    /**\n     * @internal\n     */\n    protected string $fragmentPath = '/_fragment';\n\n    /**\n     * Sets the fragment path that triggers the fragment listener.\n     *\n     * @see FragmentListener\n     */\n    public function setFragmentPath(string $path): void\n    {\n        $this->fragmentPath = $path;\n    }\n\n    /**\n     * Generates a fragment URI for a given controller.\n     *\n     * @param bool $absolute Whether to generate an absolute URL or not\n     * @param bool $strict   Whether to allow non-scalar attributes or not\n     */\n    protected function generateFragmentUri(ControllerReference $reference, Request $request, bool $absolute = false, bool $strict = true): string\n    {\n        return (new FragmentUriGenerator($this->fragmentPath))->generate($reference, $request, $absolute, $strict, false);\n    }\n}\n"
  },
  {
    "path": "Fragment/SsiFragmentRenderer.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Fragment;\n\n/**\n * Implements the SSI rendering strategy.\n *\n * @author Sebastian Krebs <krebs.seb@gmail.com>\n */\nclass SsiFragmentRenderer extends AbstractSurrogateFragmentRenderer\n{\n    public function getName(): string\n    {\n        return 'ssi';\n    }\n}\n"
  },
  {
    "path": "HttpCache/AbstractSurrogate.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\HttpCache;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\n\n/**\n * Abstract class implementing Surrogate capabilities to Request and Response instances.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n * @author Robin Chalas <robin.chalas@gmail.com>\n */\nabstract class AbstractSurrogate implements SurrogateInterface\n{\n    /**\n     * @param array $contentTypes An array of content-type that should be parsed for Surrogate information\n     *                            (default: text/html, text/xml, application/xhtml+xml, and application/xml)\n     */\n    public function __construct(\n        protected array $contentTypes = ['text/html', 'text/xml', 'application/xhtml+xml', 'application/xml'],\n    ) {\n    }\n\n    /**\n     * Returns a new cache strategy instance.\n     */\n    public function createCacheStrategy(): ResponseCacheStrategyInterface\n    {\n        return new ResponseCacheStrategy();\n    }\n\n    public function hasSurrogateCapability(Request $request): bool\n    {\n        if (null === $value = $request->headers->get('Surrogate-Capability')) {\n            return false;\n        }\n\n        return str_contains($value, \\sprintf('%s/1.0', strtoupper($this->getName())));\n    }\n\n    public function addSurrogateCapability(Request $request): void\n    {\n        $current = $request->headers->get('Surrogate-Capability');\n        $new = \\sprintf('symfony=\"%s/1.0\"', strtoupper($this->getName()));\n\n        $request->headers->set('Surrogate-Capability', $current ? $current.', '.$new : $new);\n    }\n\n    public function needsParsing(Response $response): bool\n    {\n        if (!$control = $response->headers->get('Surrogate-Control')) {\n            return false;\n        }\n\n        $pattern = \\sprintf('#content=\"[^\"]*%s/1.0[^\"]*\"#', strtoupper($this->getName()));\n\n        return (bool) preg_match($pattern, $control);\n    }\n\n    public function handle(HttpCache $cache, string $uri, string $alt, bool $ignoreErrors): string\n    {\n        $subRequest = Request::create($uri, 'GET', [], $cache->getRequest()->cookies->all(), [], $cache->getRequest()->server->all());\n\n        try {\n            $response = $cache->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true);\n\n            if (!$response->isSuccessful() && Response::HTTP_NOT_MODIFIED !== $response->getStatusCode()) {\n                throw new \\RuntimeException(\\sprintf('Error when rendering \"%s\" (Status code is %d).', $subRequest->getUri(), $response->getStatusCode()));\n            }\n\n            return $response->getContent();\n        } catch (\\Exception $e) {\n            if ($alt) {\n                return $this->handle($cache, $alt, '', $ignoreErrors);\n            }\n\n            if (!$ignoreErrors) {\n                throw $e;\n            }\n        }\n\n        return '';\n    }\n\n    /**\n     * Remove the Surrogate from the Surrogate-Control header.\n     */\n    protected function removeFromControl(Response $response): void\n    {\n        if (!$response->headers->has('Surrogate-Control')) {\n            return;\n        }\n\n        $value = $response->headers->get('Surrogate-Control');\n        $upperName = strtoupper($this->getName());\n\n        if (\\sprintf('content=\"%s/1.0\"', $upperName) == $value) {\n            $response->headers->remove('Surrogate-Control');\n        } elseif (preg_match(\\sprintf('#,\\s*content=\"%s/1.0\"#', $upperName), $value)) {\n            $response->headers->set('Surrogate-Control', preg_replace(\\sprintf('#,\\s*content=\"%s/1.0\"#', $upperName), '', $value));\n        } elseif (preg_match(\\sprintf('#content=\"%s/1.0\",\\s*#', $upperName), $value)) {\n            $response->headers->set('Surrogate-Control', preg_replace(\\sprintf('#content=\"%s/1.0\",\\s*#', $upperName), '', $value));\n        }\n    }\n\n    protected static function generateBodyEvalBoundary(): string\n    {\n        static $cookie;\n        $cookie = hash('xxh128', $cookie ?? $cookie = random_bytes(16), true);\n        $boundary = base64_encode($cookie);\n\n        \\assert(HttpCache::BODY_EVAL_BOUNDARY_LENGTH === \\strlen($boundary));\n\n        return $boundary;\n    }\n}\n"
  },
  {
    "path": "HttpCache/CacheWasLockedException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\HttpCache;\n\n/**\n * @internal\n */\nclass CacheWasLockedException extends \\Exception\n{\n}\n"
  },
  {
    "path": "HttpCache/Esi.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\HttpCache;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\n\n/**\n * Esi implements the ESI capabilities to Request and Response instances.\n *\n * For more information, read the following W3C notes:\n *\n *  * ESI Language Specification 1.0 (http://www.w3.org/TR/esi-lang)\n *\n *  * Edge Architecture Specification (http://www.w3.org/TR/edge-arch)\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass Esi extends AbstractSurrogate\n{\n    public function getName(): string\n    {\n        return 'esi';\n    }\n\n    public function addSurrogateControl(Response $response): void\n    {\n        if (str_contains($response->getContent(), '<esi:include')) {\n            $response->headers->set('Surrogate-Control', 'content=\"ESI/1.0\"');\n        }\n    }\n\n    public function renderIncludeTag(string $uri, ?string $alt = null, bool $ignoreErrors = true, string $comment = ''): string\n    {\n        $html = \\sprintf('<esi:include src=\"%s\"%s%s />',\n            $uri,\n            $ignoreErrors ? ' onerror=\"continue\"' : '',\n            $alt ? \\sprintf(' alt=\"%s\"', $alt) : ''\n        );\n\n        if ($comment) {\n            return \\sprintf(\"<esi:comment text=\\\"%s\\\" />\\n%s\", $comment, $html);\n        }\n\n        return $html;\n    }\n\n    public function process(Request $request, Response $response): Response\n    {\n        $type = $response->headers->get('Content-Type');\n        if (!$type) {\n            $type = 'text/html';\n        }\n\n        $parts = explode(';', $type);\n        if (!\\in_array($parts[0], $this->contentTypes, true)) {\n            return $response;\n        }\n\n        // we don't use a proper XML parser here as we can have ESI tags in a plain text response\n        $content = $response->getContent();\n        $content = preg_replace('#<esi\\:remove>.*?</esi\\:remove>#s', '', $content);\n        $content = preg_replace('#<esi\\:comment[^>]+>#s', '', $content);\n\n        $boundary = self::generateBodyEvalBoundary();\n        $chunks = preg_split('#<esi\\:include\\s+(.*?)\\s*(?:/|</esi\\:include)>#', $content, -1, \\PREG_SPLIT_DELIM_CAPTURE);\n\n        $i = 1;\n        while (isset($chunks[$i])) {\n            $options = [];\n            preg_match_all('/(src|onerror|alt)=\"([^\"]*?)\"/', $chunks[$i], $matches, \\PREG_SET_ORDER);\n            foreach ($matches as $set) {\n                $options[$set[1]] = $set[2];\n            }\n\n            if (!isset($options['src'])) {\n                throw new \\RuntimeException('Unable to process an ESI tag without a \"src\" attribute.');\n            }\n\n            $chunks[$i] = $boundary.$options['src'].\"\\n\".($options['alt'] ?? '').\"\\n\".('continue' === ($options['onerror'] ?? '')).\"\\n\";\n            $i += 2;\n        }\n        $content = $boundary.implode('', $chunks).$boundary;\n\n        $response->setContent($content);\n        $response->headers->set('X-Body-Eval', 'ESI');\n\n        // remove ESI/1.0 from the Surrogate-Control header\n        $this->removeFromControl($response);\n\n        return $response;\n    }\n}\n"
  },
  {
    "path": "HttpCache/HttpCache.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * This code is partially based on the Rack-Cache library by Ryan Tomayko,\n * which is released under the MIT license.\n * (based on commit 02d2b48d75bcb63cf1c0c7149c077ad256542801)\n */\n\nnamespace Symfony\\Component\\HttpKernel\\HttpCache;\n\nuse Symfony\\Component\\HttpFoundation\\Exception\\SuspiciousOperationException;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\TerminableInterface;\n\n/**\n * Cache provides HTTP caching.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass HttpCache implements HttpKernelInterface, TerminableInterface\n{\n    public const BODY_EVAL_BOUNDARY_LENGTH = 24;\n\n    private Request $request;\n    private ?ResponseCacheStrategyInterface $surrogateCacheStrategy = null;\n    private array $options = [];\n    private array $traces = [];\n\n    /**\n     * Constructor.\n     *\n     * The available options are:\n     *\n     *   * debug                  If true, exceptions are thrown when things go wrong. Otherwise, the cache\n     *                            will try to carry on and deliver a meaningful response.\n     *\n     *   * trace_level            May be one of 'none', 'short' and 'full'. For 'short', a concise trace of the\n     *                            main request will be added as an HTTP header. 'full' will add traces for all\n     *                            requests (including ESI subrequests). (default: 'full' if in debug; 'none' otherwise)\n     *\n     *   * trace_header           Header name to use for traces. (default: X-Symfony-Cache)\n     *\n     *   * default_ttl            The number of seconds that a cache entry should be considered\n     *                            fresh when no explicit freshness information is provided in\n     *                            a response. Explicit Cache-Control or Expires headers\n     *                            override this value. (default: 0)\n     *\n     *   * private_headers        Set of request headers that trigger \"private\" cache-control behavior\n     *                            on responses that don't explicitly state whether the response is\n     *                            public or private via a Cache-Control directive. (default: Authorization and Cookie)\n     *\n     *   * skip_response_headers  Set of response headers that are never cached even if a response is cacheable (public).\n     *                            (default: Set-Cookie)\n     *\n     *   * allow_reload           Specifies whether the client can force a cache reload by including a\n     *                            Cache-Control \"no-cache\" directive in the request. Set it to ``true``\n     *                            for compliance with RFC 2616. (default: false)\n     *\n     *   * allow_revalidate       Specifies whether the client can force a cache revalidate by including\n     *                            a Cache-Control \"max-age=0\" directive in the request. Set it to ``true``\n     *                            for compliance with RFC 2616. (default: false)\n     *\n     *   * stale_while_revalidate Specifies the default number of seconds (the granularity is the second as the\n     *                            Response TTL precision is a second) during which the cache can immediately return\n     *                            a stale response while it revalidates it in the background (default: 2).\n     *                            This setting is overridden by the stale-while-revalidate HTTP Cache-Control\n     *                            extension (see RFC 5861).\n     *\n     *   * stale_if_error         Specifies the default number of seconds (the granularity is the second) during which\n     *                            the cache can serve a stale response when an error is encountered (default: 60).\n     *                            This setting is overridden by the stale-if-error HTTP Cache-Control extension\n     *                            (see RFC 5861).\n     */\n    public function __construct(\n        private HttpKernelInterface $kernel,\n        private StoreInterface $store,\n        private ?SurrogateInterface $surrogate = null,\n        array $options = [],\n    ) {\n        // needed in case there is a fatal error because the backend is too slow to respond\n        register_shutdown_function($this->store->cleanup(...));\n\n        $this->options = array_merge([\n            'debug' => false,\n            'default_ttl' => 0,\n            'private_headers' => ['Authorization', 'Cookie'],\n            'skip_response_headers' => ['Set-Cookie'],\n            'allow_reload' => false,\n            'allow_revalidate' => false,\n            'stale_while_revalidate' => 2,\n            'stale_if_error' => 60,\n            'trace_level' => 'none',\n            'trace_header' => 'X-Symfony-Cache',\n        ], $options);\n\n        if (!isset($options['trace_level'])) {\n            $this->options['trace_level'] = $this->options['debug'] ? 'full' : 'none';\n        }\n    }\n\n    /**\n     * Gets the current store.\n     */\n    public function getStore(): StoreInterface\n    {\n        return $this->store;\n    }\n\n    /**\n     * Returns an array of events that took place during processing of the last request.\n     */\n    public function getTraces(): array\n    {\n        return $this->traces;\n    }\n\n    private function addTraces(Response $response): void\n    {\n        $traceString = null;\n\n        if ('full' === $this->options['trace_level']) {\n            $traceString = $this->getLog();\n        }\n\n        if ('short' === $this->options['trace_level'] && $masterId = array_key_first($this->traces)) {\n            $traceString = implode('/', $this->traces[$masterId]);\n        }\n\n        if (null !== $traceString) {\n            $response->headers->add([$this->options['trace_header'] => $traceString]);\n        }\n    }\n\n    /**\n     * Returns a log message for the events of the last request processing.\n     */\n    public function getLog(): string\n    {\n        $log = [];\n        foreach ($this->traces as $request => $traces) {\n            $log[] = \\sprintf('%s: %s', $request, implode(', ', $traces));\n        }\n\n        return implode('; ', $log);\n    }\n\n    /**\n     * Gets the Request instance associated with the main request.\n     */\n    public function getRequest(): Request\n    {\n        return $this->request;\n    }\n\n    /**\n     * Gets the Kernel instance.\n     */\n    public function getKernel(): HttpKernelInterface\n    {\n        return $this->kernel;\n    }\n\n    /**\n     * Gets the Surrogate instance.\n     *\n     * @throws \\LogicException\n     */\n    public function getSurrogate(): SurrogateInterface\n    {\n        return $this->surrogate;\n    }\n\n    public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response\n    {\n        // FIXME: catch exceptions and implement a 500 error page here? -> in Varnish, there is a built-in error page mechanism\n        if (HttpKernelInterface::MAIN_REQUEST === $type) {\n            $this->traces = [];\n            // Keep a clone of the original request for surrogates so they can access it.\n            // We must clone here to get a separate instance because the application will modify the request during\n            // the application flow (we know it always does because we do ourselves by setting REMOTE_ADDR to 127.0.0.1\n            // and adding the X-Forwarded-For header, see HttpCache::forward()).\n            $this->request = clone $request;\n            if (null !== $this->surrogate) {\n                $this->surrogateCacheStrategy = $this->surrogate->createCacheStrategy();\n            }\n        }\n\n        $this->traces[$this->getTraceKey($request)] = [];\n\n        if (!$request->isMethodSafe()) {\n            $response = $this->invalidate($request, $catch);\n        } elseif ($request->headers->has('expect') || !$request->isMethodCacheable()) {\n            $response = $this->pass($request, $catch);\n        } elseif ($this->options['allow_reload'] && $request->isNoCache()) {\n            /*\n                If allow_reload is configured and the client requests \"Cache-Control: no-cache\",\n                reload the cache by fetching a fresh response and caching it (if possible).\n            */\n            $this->record($request, 'reload');\n            $response = $this->fetch($request, $catch);\n        } else {\n            $response = null;\n            do {\n                try {\n                    $response = $this->lookup($request, $catch);\n                } catch (CacheWasLockedException) {\n                }\n            } while (null === $response);\n        }\n\n        $this->restoreResponseBody($request, $response);\n\n        if (HttpKernelInterface::MAIN_REQUEST === $type) {\n            $this->addTraces($response);\n        }\n\n        if (null !== $this->surrogate) {\n            if (HttpKernelInterface::MAIN_REQUEST === $type) {\n                $this->surrogateCacheStrategy->update($response);\n            } else {\n                $this->surrogateCacheStrategy->add($response);\n            }\n        }\n\n        $response->prepare($request);\n\n        if (HttpKernelInterface::MAIN_REQUEST === $type) {\n            $response->isNotModified($request);\n        }\n\n        return $response;\n    }\n\n    public function terminate(Request $request, Response $response): void\n    {\n        // Do not call any listeners in case of a cache hit.\n        // This ensures identical behavior as if you had a separate\n        // reverse caching proxy such as Varnish and the like.\n        if (\\in_array('fresh', $this->traces[$this->getTraceKey($request)] ?? [], true)) {\n            return;\n        }\n\n        if ($this->getKernel() instanceof TerminableInterface) {\n            $this->getKernel()->terminate($request, $response);\n        }\n    }\n\n    /**\n     * Forwards the Request to the backend without storing the Response in the cache.\n     *\n     * @param bool $catch Whether to process exceptions\n     */\n    protected function pass(Request $request, bool $catch = false): Response\n    {\n        $this->record($request, 'pass');\n\n        return $this->forward($request, $catch);\n    }\n\n    /**\n     * Invalidates non-safe methods (like POST, PUT, and DELETE).\n     *\n     * @param bool $catch Whether to process exceptions\n     *\n     * @throws \\Exception\n     *\n     * @see RFC2616 13.10\n     */\n    protected function invalidate(Request $request, bool $catch = false): Response\n    {\n        $response = $this->pass($request, $catch);\n\n        // invalidate only when the response is successful\n        if ($response->isSuccessful() || $response->isRedirect()) {\n            try {\n                $this->store->invalidate($request);\n\n                // As per the RFC, invalidate Location and Content-Location URLs if present\n                foreach (['Location', 'Content-Location'] as $header) {\n                    if ($uri = $response->headers->get($header)) {\n                        $subRequest = Request::create($uri, 'get', [], [], [], $request->server->all());\n\n                        $this->store->invalidate($subRequest);\n                    }\n                }\n\n                $this->record($request, 'invalidate');\n            } catch (\\Exception $e) {\n                $this->record($request, 'invalidate-failed');\n\n                if ($this->options['debug']) {\n                    throw $e;\n                }\n            }\n        }\n\n        return $response;\n    }\n\n    /**\n     * Lookups a Response from the cache for the given Request.\n     *\n     * When a matching cache entry is found and is fresh, it uses it as the\n     * response without forwarding any request to the backend. When a matching\n     * cache entry is found but is stale, it attempts to \"validate\" the entry with\n     * the backend using conditional GET. When no matching cache entry is found,\n     * it triggers \"miss\" processing.\n     *\n     * @param bool $catch Whether to process exceptions\n     *\n     * @throws \\Exception\n     */\n    protected function lookup(Request $request, bool $catch = false): Response\n    {\n        try {\n            $entry = $this->store->lookup($request);\n        } catch (\\Exception $e) {\n            $this->record($request, 'lookup-failed');\n\n            if ($this->options['debug']) {\n                throw $e;\n            }\n\n            return $this->pass($request, $catch);\n        }\n\n        if (null === $entry) {\n            $this->record($request, 'miss');\n\n            return $this->fetch($request, $catch);\n        }\n\n        if (!$this->isFreshEnough($request, $entry)) {\n            $this->record($request, 'stale');\n\n            return $this->validate($request, $entry, $catch);\n        }\n\n        if ($entry->headers->hasCacheControlDirective('no-cache')) {\n            return $this->validate($request, $entry, $catch);\n        }\n\n        $this->record($request, 'fresh');\n\n        $entry->headers->set('Age', $entry->getAge());\n\n        return $entry;\n    }\n\n    /**\n     * Validates that a cache entry is fresh.\n     *\n     * The original request is used as a template for a conditional\n     * GET request with the backend.\n     *\n     * @param bool $catch Whether to process exceptions\n     */\n    protected function validate(Request $request, Response $entry, bool $catch = false): Response\n    {\n        $subRequest = clone $request;\n\n        // send no head requests because we want content\n        if ('HEAD' === $request->getMethod()) {\n            $subRequest->setMethod('GET');\n        }\n\n        // add our cached last-modified validator\n        if ($entry->headers->has('Last-Modified')) {\n            $subRequest->headers->set('If-Modified-Since', $entry->headers->get('Last-Modified'));\n        }\n\n        // Add our cached etag validator to the environment.\n        // We keep the etags from the client to handle the case when the client\n        // has a different private valid entry which is not cached here.\n        $cachedEtags = $entry->getEtag() ? [$entry->getEtag()] : [];\n        $requestEtags = $request->getETags();\n        if ($etags = array_unique(array_merge($cachedEtags, $requestEtags))) {\n            $subRequest->headers->set('If-None-Match', implode(', ', $etags));\n        }\n\n        $response = $this->forward($subRequest, $catch, $entry);\n\n        if (304 == $response->getStatusCode()) {\n            $this->record($request, 'valid');\n\n            // return the response and not the cache entry if the response is valid but not cached\n            $etag = $response->getEtag();\n            if ($etag && \\in_array($etag, $requestEtags, true) && !\\in_array($etag, $cachedEtags, true)) {\n                return $response;\n            }\n\n            $entry = clone $entry;\n            $entry->headers->remove('Date');\n\n            foreach (['Date', 'Expires', 'Cache-Control', 'ETag', 'Last-Modified'] as $name) {\n                if ($response->headers->has($name)) {\n                    $entry->headers->set($name, $response->headers->get($name));\n                }\n            }\n\n            $response = $entry;\n        } else {\n            $this->record($request, 'invalid');\n        }\n\n        if ($response->isCacheable()) {\n            $this->store($request, $response);\n        }\n\n        return $response;\n    }\n\n    /**\n     * Unconditionally fetches a fresh response from the backend and\n     * stores it in the cache if is cacheable.\n     *\n     * @param bool $catch Whether to process exceptions\n     */\n    protected function fetch(Request $request, bool $catch = false): Response\n    {\n        $subRequest = clone $request;\n\n        // send no head requests because we want content\n        if ('HEAD' === $request->getMethod()) {\n            $subRequest->setMethod('GET');\n        }\n\n        // avoid that the backend sends no content\n        $subRequest->headers->remove('If-Modified-Since');\n        $subRequest->headers->remove('If-None-Match');\n\n        $response = $this->forward($subRequest, $catch);\n\n        if ($response->isCacheable()) {\n            $this->store($request, $response);\n        }\n\n        return $response;\n    }\n\n    /**\n     * Forwards the Request to the backend and returns the Response.\n     *\n     * All backend requests (cache passes, fetches, cache validations)\n     * run through this method.\n     *\n     * @param bool          $catch Whether to catch exceptions or not\n     * @param Response|null $entry A Response instance (the stale entry if present, null otherwise)\n     */\n    protected function forward(Request $request, bool $catch = false, ?Response $entry = null): Response\n    {\n        $this->surrogate?->addSurrogateCapability($request);\n\n        // always a \"master\" request (as the real master request can be in cache)\n        $response = SubRequestHandler::handle($this->kernel, $request, HttpKernelInterface::MAIN_REQUEST, $catch);\n\n        /*\n         * Support stale-if-error given on Responses or as a config option.\n         * RFC 7234 summarizes in Section 4.2.4 (but also mentions with the individual\n         * Cache-Control directives) that\n         *\n         *      A cache MUST NOT generate a stale response if it is prohibited by an\n         *      explicit in-protocol directive (e.g., by a \"no-store\" or \"no-cache\"\n         *      cache directive, a \"must-revalidate\" cache-response-directive, or an\n         *      applicable \"s-maxage\" or \"proxy-revalidate\" cache-response-directive;\n         *      see Section 5.2.2).\n         *\n         * https://tools.ietf.org/html/rfc7234#section-4.2.4\n         *\n         * We deviate from this in one detail, namely that we *do* serve entries in the\n         * stale-if-error case even if they have a `s-maxage` Cache-Control directive.\n         */\n        if (null !== $entry\n            && \\in_array($response->getStatusCode(), [500, 502, 503, 504], true)\n            && !$entry->headers->hasCacheControlDirective('no-cache')\n            && !$entry->mustRevalidate()\n        ) {\n            if (null === $age = $entry->headers->getCacheControlDirective('stale-if-error')) {\n                $age = $this->options['stale_if_error'];\n            }\n\n            /*\n             * stale-if-error gives the (extra) time that the Response may be used *after* it has become stale.\n             * So we compare the time the $entry has been sitting in the cache already with the\n             * time it was fresh plus the allowed grace period.\n             */\n            if ($entry->getAge() <= $entry->getMaxAge() + $age) {\n                $this->record($request, 'stale-if-error');\n\n                return $entry;\n            }\n        }\n\n        /*\n            RFC 7231 Sect. 7.1.1.2 says that a server that does not have a reasonably accurate\n            clock MUST NOT send a \"Date\" header, although it MUST send one in most other cases\n            except for 1xx or 5xx responses where it MAY do so.\n\n            Anyway, a client that received a message without a \"Date\" header MUST add it.\n        */\n        if (!$response->headers->has('Date')) {\n            $response->setDate(\\DateTimeImmutable::createFromFormat('U', time()));\n        }\n\n        $this->processResponseBody($request, $response);\n\n        if ($this->isPrivateRequest($request) && !$response->headers->hasCacheControlDirective('public')) {\n            $response->setPrivate();\n        } elseif ($this->options['default_ttl'] > 0 && null === $response->getTtl() && !$response->headers->getCacheControlDirective('must-revalidate')) {\n            $response->setTtl($this->options['default_ttl']);\n        }\n\n        return $response;\n    }\n\n    /**\n     * Checks whether the cache entry is \"fresh enough\" to satisfy the Request.\n     */\n    protected function isFreshEnough(Request $request, Response $entry): bool\n    {\n        if (!$entry->isFresh()) {\n            return $this->lock($request, $entry);\n        }\n\n        if ($this->options['allow_revalidate'] && null !== $maxAge = $request->headers->getCacheControlDirective('max-age')) {\n            return $maxAge > 0 && $maxAge >= $entry->getAge();\n        }\n\n        return true;\n    }\n\n    /**\n     * Locks a Request during the call to the backend.\n     *\n     * @return bool true if the cache entry can be returned even if it is staled, false otherwise\n     */\n    protected function lock(Request $request, Response $entry): bool\n    {\n        // try to acquire a lock to call the backend\n        $lock = $this->store->lock($request);\n\n        if (true === $lock) {\n            // we have the lock, call the backend\n            return false;\n        }\n\n        // there is already another process calling the backend\n\n        // May we serve a stale response?\n        if ($this->mayServeStaleWhileRevalidate($entry)) {\n            $this->record($request, 'stale-while-revalidate');\n\n            return true;\n        }\n\n        $this->record($request, 'waiting');\n\n        // wait for the lock to be released\n        if ($this->waitForLock($request)) {\n            throw new CacheWasLockedException(); // unwind back to handle(), try again\n        }\n\n        // backend is slow as hell, send a 503 response (to avoid the dog pile effect)\n        $entry->setStatusCode(503);\n        $entry->setContent('503 Service Unavailable');\n        $entry->headers->set('Retry-After', 10);\n\n        return true;\n    }\n\n    /**\n     * Writes the Response to the cache.\n     *\n     * @throws \\Exception\n     */\n    protected function store(Request $request, Response $response): void\n    {\n        try {\n            $restoreHeaders = [];\n            foreach ($this->options['skip_response_headers'] as $header) {\n                if (!$response->headers->has($header)) {\n                    continue;\n                }\n\n                $restoreHeaders[$header] = $response->headers->all($header);\n                $response->headers->remove($header);\n            }\n\n            $this->store->write($request, $response);\n            $this->record($request, 'store');\n\n            $response->headers->set('Age', $response->getAge());\n        } catch (\\Exception $e) {\n            $this->record($request, 'store-failed');\n\n            if ($this->options['debug']) {\n                throw $e;\n            }\n        } finally {\n            foreach ($restoreHeaders as $header => $values) {\n                $response->headers->set($header, $values);\n            }\n        }\n\n        // now that the response is cached, release the lock\n        $this->store->unlock($request);\n    }\n\n    /**\n     * Restores the Response body.\n     */\n    private function restoreResponseBody(Request $request, Response $response): void\n    {\n        if ($response->headers->has('X-Body-Eval')) {\n            \\assert(self::BODY_EVAL_BOUNDARY_LENGTH === 24);\n\n            ob_start();\n\n            $content = $response->getContent();\n            $boundary = substr($content, 0, 24);\n            $j = strpos($content, $boundary, 24);\n            echo substr($content, 24, $j - 24);\n            $i = $j + 24;\n\n            while (false !== $j = strpos($content, $boundary, $i)) {\n                [$uri, $alt, $ignoreErrors, $part] = explode(\"\\n\", substr($content, $i, $j - $i), 4);\n                $i = $j + 24;\n\n                echo $this->surrogate->handle($this, $uri, $alt, $ignoreErrors);\n                echo $part;\n            }\n\n            $response->setContent(ob_get_clean());\n            $response->headers->remove('X-Body-Eval');\n            if (!$response->headers->has('Transfer-Encoding')) {\n                $response->headers->set('Content-Length', \\strlen($response->getContent()));\n            }\n        } elseif ($response->headers->has('X-Body-File')) {\n            // Response does not include possibly dynamic content (ESI, SSI), so we need\n            // not handle the content for HEAD requests\n            if (!$request->isMethod('HEAD')) {\n                $response->setContent(file_get_contents($response->headers->get('X-Body-File')));\n            }\n        } else {\n            return;\n        }\n\n        $response->headers->remove('X-Body-File');\n    }\n\n    protected function processResponseBody(Request $request, Response $response): void\n    {\n        if ($this->surrogate?->needsParsing($response)) {\n            $this->surrogate->process($request, $response);\n        }\n    }\n\n    /**\n     * Checks if the Request includes authorization or other sensitive information\n     * that should cause the Response to be considered private by default.\n     */\n    private function isPrivateRequest(Request $request): bool\n    {\n        foreach ($this->options['private_headers'] as $key) {\n            $key = strtolower(str_replace('HTTP_', '', $key));\n\n            if ('cookie' === $key) {\n                if (\\count($request->cookies->all())) {\n                    return true;\n                }\n            } elseif ($request->headers->has($key)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Records that an event took place.\n     */\n    private function record(Request $request, string $event): void\n    {\n        $this->traces[$this->getTraceKey($request)][] = $event;\n    }\n\n    /**\n     * Calculates the key we use in the \"trace\" array for a given request.\n     */\n    private function getTraceKey(Request $request): string\n    {\n        $path = $request->getPathInfo();\n        if ($qs = $request->getQueryString()) {\n            $path .= '?'.$qs;\n        }\n\n        try {\n            return $request->getMethod().' '.$path;\n        } catch (SuspiciousOperationException) {\n            return '_BAD_METHOD_ '.$path;\n        }\n    }\n\n    /**\n     * Checks whether the given (cached) response may be served as \"stale\" when a revalidation\n     * is currently in progress.\n     */\n    private function mayServeStaleWhileRevalidate(Response $entry): bool\n    {\n        $timeout = $entry->headers->getCacheControlDirective('stale-while-revalidate');\n        $timeout ??= $this->options['stale_while_revalidate'];\n\n        $age = $entry->getAge();\n        $maxAge = $entry->getMaxAge() ?? 0;\n        $ttl = $maxAge - $age;\n\n        return abs($ttl) < $timeout;\n    }\n\n    /**\n     * Waits for the store to release a locked entry.\n     */\n    private function waitForLock(Request $request): bool\n    {\n        $wait = 0;\n        while ($this->store->isLocked($request) && $wait < 100) {\n            usleep(50000);\n            ++$wait;\n        }\n\n        return $wait < 100;\n    }\n}\n"
  },
  {
    "path": "HttpCache/ResponseCacheStrategy.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\HttpCache;\n\nuse Symfony\\Component\\HttpFoundation\\Response;\n\n/**\n * ResponseCacheStrategy knows how to compute the Response cache HTTP header\n * based on the different response cache headers.\n *\n * This implementation changes the main response TTL to the smallest TTL received\n * or force validation if one of the surrogates has validation cache strategy.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass ResponseCacheStrategy implements ResponseCacheStrategyInterface\n{\n    /**\n     * Cache-Control headers that are sent to the final response if they appear in ANY of the responses.\n     */\n    private const OVERRIDE_DIRECTIVES = ['private', 'no-cache', 'no-store', 'no-transform', 'must-revalidate', 'proxy-revalidate'];\n\n    /**\n     * Cache-Control headers that are sent to the final response if they appear in ALL of the responses.\n     */\n    private const INHERIT_DIRECTIVES = ['public', 'immutable'];\n\n    private int $embeddedResponses = 0;\n    private bool $isNotCacheableResponseEmbedded = false;\n    private int $age = 0;\n    private \\DateTimeInterface|false|null $lastModified = null;\n    private array $flagDirectives = [\n        'no-cache' => null,\n        'no-store' => null,\n        'no-transform' => null,\n        'must-revalidate' => null,\n        'proxy-revalidate' => null,\n        'public' => null,\n        'private' => null,\n        'immutable' => null,\n    ];\n    private array $ageDirectives = [\n        'max-age' => null,\n        's-maxage' => null,\n        'expires' => false,\n    ];\n\n    public function add(Response $response): void\n    {\n        ++$this->embeddedResponses;\n\n        foreach (self::OVERRIDE_DIRECTIVES as $directive) {\n            if ($response->headers->hasCacheControlDirective($directive)) {\n                $this->flagDirectives[$directive] = true;\n            }\n        }\n\n        foreach (self::INHERIT_DIRECTIVES as $directive) {\n            if (false !== $this->flagDirectives[$directive]) {\n                $this->flagDirectives[$directive] = $response->headers->hasCacheControlDirective($directive);\n            }\n        }\n\n        $age = $response->getAge();\n        $this->age = max($this->age, $age);\n\n        if ($this->willMakeFinalResponseUncacheable($response)) {\n            $this->isNotCacheableResponseEmbedded = true;\n\n            return;\n        }\n\n        $maxAge = $response->headers->hasCacheControlDirective('max-age') ? (int) $response->headers->getCacheControlDirective('max-age') : null;\n        $sharedMaxAge = $response->headers->hasCacheControlDirective('s-maxage') ? (int) $response->headers->getCacheControlDirective('s-maxage') : $maxAge;\n        $expires = $response->getExpires();\n        $expires = null !== $expires ? (int) $expires->format('U') - (int) $response->getDate()->format('U') : null;\n\n        // See https://datatracker.ietf.org/doc/html/rfc7234#section-4.2.2\n        // If a response is \"public\" but does not have maximum lifetime, heuristics might be applied.\n        // Do not store NULL values so the final response can have more limiting value from other responses.\n        $isHeuristicallyCacheable = $response->headers->hasCacheControlDirective('public')\n            && null === $maxAge\n            && null === $sharedMaxAge\n            && null === $expires;\n\n        if (!$isHeuristicallyCacheable || null !== $maxAge || null !== $expires) {\n            $this->storeRelativeAgeDirective('max-age', $maxAge, $expires, $age);\n        }\n\n        if (!$isHeuristicallyCacheable || null !== $sharedMaxAge || null !== $expires) {\n            $this->storeRelativeAgeDirective('s-maxage', $sharedMaxAge, $expires, $age);\n        }\n\n        if (null !== $expires) {\n            $this->ageDirectives['expires'] = true;\n        }\n\n        if (false !== $this->lastModified) {\n            $lastModified = $response->getLastModified();\n            $this->lastModified = $lastModified ? max($this->lastModified, $lastModified) : false;\n        }\n    }\n\n    public function update(Response $response): void\n    {\n        // if we have no embedded Response, do nothing\n        if (0 === $this->embeddedResponses) {\n            return;\n        }\n\n        // Remove Etag since it cannot be merged from embedded responses.\n        $response->setEtag(null);\n\n        $this->add($response);\n\n        $response->headers->set('Age', $this->age);\n\n        if ($this->isNotCacheableResponseEmbedded) {\n            $response->setLastModified(null);\n\n            if ($this->flagDirectives['no-store']) {\n                $response->headers->set('Cache-Control', 'no-cache, no-store, must-revalidate');\n            } else {\n                $response->headers->set('Cache-Control', 'no-cache, must-revalidate');\n            }\n\n            return;\n        }\n\n        $response->setLastModified($this->lastModified ?: null);\n\n        $flags = array_filter($this->flagDirectives);\n\n        if (isset($flags['must-revalidate'])) {\n            $flags['no-cache'] = true;\n        }\n\n        $response->headers->set('Cache-Control', implode(', ', array_keys($flags)));\n\n        $maxAge = null;\n\n        if (is_numeric($this->ageDirectives['max-age'])) {\n            $maxAge = $this->ageDirectives['max-age'] + $this->age;\n            $response->headers->addCacheControlDirective('max-age', $maxAge);\n        }\n\n        if (is_numeric($this->ageDirectives['s-maxage'])) {\n            $sMaxage = $this->ageDirectives['s-maxage'] + $this->age;\n\n            if ($maxAge !== $sMaxage) {\n                $response->headers->addCacheControlDirective('s-maxage', $sMaxage);\n            }\n        }\n\n        if ($this->ageDirectives['expires'] && null !== $maxAge) {\n            $date = clone $response->getDate();\n            $date = $date->modify('+'.$maxAge.' seconds');\n            $response->setExpires($date);\n        }\n    }\n\n    /**\n     * RFC2616, Section 13.4.\n     *\n     * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.4\n     */\n    private function willMakeFinalResponseUncacheable(Response $response): bool\n    {\n        // RFC2616: A response received with a status code of 200, 203, 300, 301 or 410\n        // MAY be stored by a cache […] unless a cache-control directive prohibits caching.\n        if ($response->headers->hasCacheControlDirective('no-cache')\n            || $response->headers->hasCacheControlDirective('no-store')\n        ) {\n            return true;\n        }\n\n        // Etag headers cannot be merged, they render the response uncacheable\n        // by default (except if the response also has max-age etc.).\n        if (null === $response->getEtag() && \\in_array($response->getStatusCode(), [200, 203, 300, 301, 410], true)) {\n            return false;\n        }\n\n        // RFC2616: A response received with any other status code (e.g. status codes 302 and 307)\n        // MUST NOT be returned in a reply to a subsequent request unless there are\n        // cache-control directives or another header(s) that explicitly allow it.\n        $cacheControl = ['max-age', 's-maxage', 'must-revalidate', 'proxy-revalidate', 'public', 'private'];\n        foreach ($cacheControl as $key) {\n            if ($response->headers->hasCacheControlDirective($key)) {\n                return false;\n            }\n        }\n\n        if ($response->headers->has('Expires')) {\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * Store lowest max-age/s-maxage/expires for the final response.\n     *\n     * The response might have been stored in cache a while ago. To keep things comparable,\n     * we have to subtract the age so that the value is normalized for an age of 0.\n     *\n     * If the value is lower than the currently stored value, we update the value, to keep a rolling\n     * minimal value of each instruction. If the value is NULL, the directive will not be set on the final response.\n     */\n    private function storeRelativeAgeDirective(string $directive, ?int $value, ?int $expires, int $age): void\n    {\n        if (null === $value && null === $expires) {\n            $this->ageDirectives[$directive] = false;\n        }\n\n        if (false !== $this->ageDirectives[$directive]) {\n            $value = min($value ?? \\PHP_INT_MAX, $expires ?? \\PHP_INT_MAX);\n            $value -= $age;\n            $this->ageDirectives[$directive] = null !== $this->ageDirectives[$directive] ? min($this->ageDirectives[$directive], $value) : $value;\n        }\n    }\n}\n"
  },
  {
    "path": "HttpCache/ResponseCacheStrategyInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * This code is partially based on the Rack-Cache library by Ryan Tomayko,\n * which is released under the MIT license.\n * (based on commit 02d2b48d75bcb63cf1c0c7149c077ad256542801)\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\HttpCache;\n\nuse Symfony\\Component\\HttpFoundation\\Response;\n\n/**\n * ResponseCacheStrategyInterface implementations know how to compute the\n * Response cache HTTP header based on the different response cache headers.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface ResponseCacheStrategyInterface\n{\n    /**\n     * Adds a Response.\n     */\n    public function add(Response $response): void;\n\n    /**\n     * Updates the Response HTTP headers based on the embedded Responses.\n     */\n    public function update(Response $response): void;\n}\n"
  },
  {
    "path": "HttpCache/Ssi.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\HttpCache;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\n\n/**\n * Ssi implements the SSI capabilities to Request and Response instances.\n *\n * @author Sebastian Krebs <krebs.seb@gmail.com>\n */\nclass Ssi extends AbstractSurrogate\n{\n    public function getName(): string\n    {\n        return 'ssi';\n    }\n\n    public function addSurrogateControl(Response $response): void\n    {\n        if (str_contains($response->getContent(), '<!--#include')) {\n            $response->headers->set('Surrogate-Control', 'content=\"SSI/1.0\"');\n        }\n    }\n\n    public function renderIncludeTag(string $uri, ?string $alt = null, bool $ignoreErrors = true, string $comment = ''): string\n    {\n        return \\sprintf('<!--#include virtual=\"%s\" -->', $uri);\n    }\n\n    public function process(Request $request, Response $response): Response\n    {\n        $type = $response->headers->get('Content-Type');\n        if (!$type) {\n            $type = 'text/html';\n        }\n\n        $parts = explode(';', $type);\n        if (!\\in_array($parts[0], $this->contentTypes, true)) {\n            return $response;\n        }\n\n        // we don't use a proper XML parser here as we can have SSI tags in a plain text response\n        $content = $response->getContent();\n        $boundary = self::generateBodyEvalBoundary();\n        $chunks = preg_split('#<!--\\#include\\s+(.*?)\\s*-->#', $content, -1, \\PREG_SPLIT_DELIM_CAPTURE);\n\n        $i = 1;\n        while (isset($chunks[$i])) {\n            $options = [];\n            preg_match_all('/(virtual)=\"([^\"]*?)\"/', $chunks[$i], $matches, \\PREG_SET_ORDER);\n            foreach ($matches as $set) {\n                $options[$set[1]] = $set[2];\n            }\n\n            if (!isset($options['virtual'])) {\n                throw new \\RuntimeException('Unable to process an SSI tag without a \"virtual\" attribute.');\n            }\n\n            $chunks[$i] = $boundary.$options['virtual'].\"\\n\\n\\n\";\n            $i += 2;\n        }\n        $content = $boundary.implode('', $chunks).$boundary;\n\n        $response->setContent($content);\n        $response->headers->set('X-Body-Eval', 'SSI');\n\n        // remove SSI/1.0 from the Surrogate-Control header\n        $this->removeFromControl($response);\n\n        return $response;\n    }\n}\n"
  },
  {
    "path": "HttpCache/Store.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * This code is partially based on the Rack-Cache library by Ryan Tomayko,\n * which is released under the MIT license.\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\HttpCache;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\n\n/**\n * Store implements all the logic for storing cache metadata (Request and Response headers).\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass Store implements StoreInterface\n{\n    /** @var \\SplObjectStorage<Request, string> */\n    private \\SplObjectStorage $keyCache;\n    /** @var array<string, resource> */\n    private array $locks = [];\n\n    /**\n     * Constructor.\n     *\n     * The available options are:\n     *\n     *   * private_headers  Set of response headers that should not be stored\n     *                      when a response is cached. (default: Set-Cookie)\n     *\n     * @throws \\RuntimeException\n     */\n    public function __construct(\n        protected string $root,\n        private array $options = [],\n    ) {\n        if (!is_dir($this->root) && !@mkdir($this->root, 0o777, true) && !is_dir($this->root)) {\n            throw new \\RuntimeException(\\sprintf('Unable to create the store directory (%s).', $this->root));\n        }\n        $this->keyCache = new \\SplObjectStorage();\n        $this->options['private_headers'] ??= ['Set-Cookie'];\n    }\n\n    /**\n     * Cleanups storage.\n     */\n    public function cleanup(): void\n    {\n        // unlock everything\n        foreach ($this->locks as $lock) {\n            flock($lock, \\LOCK_UN);\n            fclose($lock);\n        }\n\n        $this->locks = [];\n    }\n\n    /**\n     * Tries to lock the cache for a given Request, without blocking.\n     *\n     * @return bool|string true if the lock is acquired, the path to the current lock otherwise\n     */\n    public function lock(Request $request): bool|string\n    {\n        $key = $this->getCacheKey($request);\n\n        if (!isset($this->locks[$key])) {\n            $path = $this->getPath($key);\n            if (!is_dir(\\dirname($path)) && false === @mkdir(\\dirname($path), 0o777, true) && !is_dir(\\dirname($path))) {\n                return $path;\n            }\n            $h = fopen($path, 'c');\n            if (!flock($h, \\LOCK_EX | \\LOCK_NB)) {\n                fclose($h);\n\n                return $path;\n            }\n\n            $this->locks[$key] = $h;\n        }\n\n        return true;\n    }\n\n    /**\n     * Releases the lock for the given Request.\n     *\n     * @return bool False if the lock file does not exist or cannot be unlocked, true otherwise\n     */\n    public function unlock(Request $request): bool\n    {\n        $key = $this->getCacheKey($request);\n\n        if (isset($this->locks[$key])) {\n            flock($this->locks[$key], \\LOCK_UN);\n            fclose($this->locks[$key]);\n            unset($this->locks[$key]);\n\n            return true;\n        }\n\n        return false;\n    }\n\n    public function isLocked(Request $request): bool\n    {\n        $key = $this->getCacheKey($request);\n\n        if (isset($this->locks[$key])) {\n            return true; // shortcut if lock held by this process\n        }\n\n        if (!is_file($path = $this->getPath($key))) {\n            return false;\n        }\n\n        $h = fopen($path, 'r');\n        flock($h, \\LOCK_EX | \\LOCK_NB, $wouldBlock);\n        flock($h, \\LOCK_UN); // release the lock we just acquired\n        fclose($h);\n\n        return (bool) $wouldBlock;\n    }\n\n    /**\n     * Locates a cached Response for the Request provided.\n     */\n    public function lookup(Request $request): ?Response\n    {\n        $key = $this->getCacheKey($request);\n\n        if (!$entries = $this->getMetadata($key)) {\n            return null;\n        }\n\n        // find a cached entry that matches the request.\n        $match = null;\n        foreach ($entries as $entry) {\n            if ($this->requestsMatch(isset($entry[1]['vary'][0]) ? implode(', ', $entry[1]['vary']) : '', $request->headers->all(), $entry[0])) {\n                $match = $entry;\n\n                break;\n            }\n        }\n\n        if (null === $match) {\n            return null;\n        }\n\n        $headers = $match[1];\n        if (file_exists($path = $this->getPath($headers['x-content-digest'][0]))) {\n            return $this->restoreResponse($headers, $path);\n        }\n\n        // TODO the metaStore referenced an entity that doesn't exist in\n        // the entityStore. We definitely want to return nil but we should\n        // also purge the entry from the meta-store when this is detected.\n        return null;\n    }\n\n    /**\n     * Writes a cache entry to the store for the given Request and Response.\n     *\n     * Existing entries are read and any that match the response are removed. This\n     * method calls write with the new list of cache entries.\n     *\n     * @throws \\RuntimeException\n     */\n    public function write(Request $request, Response $response): string\n    {\n        $key = $this->getCacheKey($request);\n        $storedEnv = $this->persistRequest($request);\n\n        if ($response->headers->has('X-Body-File')) {\n            // Assume the response came from disk, but at least perform some safeguard checks\n            if (!$response->headers->has('X-Content-Digest')) {\n                throw new \\RuntimeException('A restored response must have the X-Content-Digest header.');\n            }\n\n            $digest = $response->headers->get('X-Content-Digest');\n            if ($this->getPath($digest) !== $response->headers->get('X-Body-File')) {\n                throw new \\RuntimeException('X-Body-File and X-Content-Digest do not match.');\n            }\n        // Everything seems ok, omit writing content to disk\n        } else {\n            $digest = $this->generateContentDigest($response);\n            $response->headers->set('X-Content-Digest', $digest);\n\n            if (!$this->save($digest, $response->getContent(), false)) {\n                throw new \\RuntimeException('Unable to store the entity.');\n            }\n\n            if (!$response->headers->has('Transfer-Encoding')) {\n                $response->headers->set('Content-Length', \\strlen($response->getContent()));\n            }\n        }\n\n        // read existing cache entries, remove non-varying, and add this one to the list\n        $entries = [];\n        $vary = implode(', ', $response->headers->all('vary'));\n        foreach ($this->getMetadata($key) as $entry) {\n            if (!$this->requestsMatch($vary ?? '', $entry[0], $storedEnv)) {\n                $entries[] = $entry;\n            }\n        }\n\n        $headers = $this->persistResponse($response);\n        unset($headers['age']);\n\n        foreach ($this->options['private_headers'] as $h) {\n            unset($headers[strtolower($h)]);\n        }\n\n        array_unshift($entries, [$storedEnv, $headers]);\n\n        if (!$this->save($key, serialize($entries))) {\n            throw new \\RuntimeException('Unable to store the metadata.');\n        }\n\n        return $key;\n    }\n\n    /**\n     * Returns content digest for $response.\n     */\n    protected function generateContentDigest(Response $response): string\n    {\n        return 'en'.hash('xxh128', $response->getContent());\n    }\n\n    /**\n     * Invalidates all cache entries that match the request.\n     *\n     * @throws \\RuntimeException\n     */\n    public function invalidate(Request $request): void\n    {\n        $modified = false;\n        $key = $this->getCacheKey($request);\n\n        $entries = [];\n        foreach ($this->getMetadata($key) as $entry) {\n            $response = $this->restoreResponse($entry[1]);\n            if ($response->isFresh()) {\n                $response->expire();\n                $modified = true;\n                $entries[] = [$entry[0], $this->persistResponse($response)];\n            } else {\n                $entries[] = $entry;\n            }\n        }\n\n        if ($modified && !$this->save($key, serialize($entries))) {\n            throw new \\RuntimeException('Unable to store the metadata.');\n        }\n    }\n\n    /**\n     * Determines whether two Request HTTP header sets are non-varying based on\n     * the vary response header value provided.\n     *\n     * @param string|null $vary A Response vary header\n     * @param array       $env1 A Request HTTP header array\n     * @param array       $env2 A Request HTTP header array\n     */\n    private function requestsMatch(?string $vary, array $env1, array $env2): bool\n    {\n        if ('' === ($vary ?? '')) {\n            return true;\n        }\n\n        foreach (preg_split('/[\\s,]+/', $vary) as $header) {\n            $key = str_replace('_', '-', strtolower($header));\n            $v1 = $env1[$key] ?? null;\n            $v2 = $env2[$key] ?? null;\n            if ($v1 !== $v2) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Gets all data associated with the given key.\n     *\n     * Use this method only if you know what you are doing.\n     */\n    private function getMetadata(string $key): array\n    {\n        if (!$entries = $this->load($key)) {\n            return [];\n        }\n\n        return unserialize($entries) ?: [];\n    }\n\n    /**\n     * Purges data for the given URL.\n     *\n     * This method purges both the HTTP and the HTTPS version of the cache entry.\n     *\n     * @return bool true if the URL exists with either HTTP or HTTPS scheme and has been purged, false otherwise\n     */\n    public function purge(string $url): bool\n    {\n        $http = preg_replace('#^https:#', 'http:', $url);\n        $https = preg_replace('#^http:#', 'https:', $url);\n\n        $purgedHttp = $this->doPurge($http);\n        $purgedHttps = $this->doPurge($https);\n\n        return $purgedHttp || $purgedHttps;\n    }\n\n    /**\n     * Purges data for the given URL.\n     */\n    private function doPurge(string $url): bool\n    {\n        $key = $this->getCacheKey(Request::create($url));\n        if (isset($this->locks[$key])) {\n            flock($this->locks[$key], \\LOCK_UN);\n            fclose($this->locks[$key]);\n            unset($this->locks[$key]);\n        }\n\n        if (is_file($path = $this->getPath($key))) {\n            unlink($path);\n\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Loads data for the given key.\n     */\n    private function load(string $key): ?string\n    {\n        $path = $this->getPath($key);\n\n        return is_file($path) && false !== ($contents = @file_get_contents($path)) ? $contents : null;\n    }\n\n    /**\n     * Save data for the given key.\n     */\n    private function save(string $key, string $data, bool $overwrite = true): bool\n    {\n        $path = $this->getPath($key);\n\n        if (!$overwrite && file_exists($path)) {\n            return true;\n        }\n\n        if (isset($this->locks[$key])) {\n            $fp = $this->locks[$key];\n            @ftruncate($fp, 0);\n            @fseek($fp, 0);\n            $len = @fwrite($fp, $data);\n            if (\\strlen($data) !== $len) {\n                @ftruncate($fp, 0);\n\n                return false;\n            }\n        } else {\n            if (!is_dir(\\dirname($path)) && false === @mkdir(\\dirname($path), 0o777, true) && !is_dir(\\dirname($path))) {\n                return false;\n            }\n\n            $tmpFile = tempnam(\\dirname($path), basename($path));\n            if (false === $fp = @fopen($tmpFile, 'w')) {\n                @unlink($tmpFile);\n\n                return false;\n            }\n            @fwrite($fp, $data);\n            @fclose($fp);\n\n            if ($data != file_get_contents($tmpFile)) {\n                @unlink($tmpFile);\n\n                return false;\n            }\n\n            if (false === @rename($tmpFile, $path)) {\n                @unlink($tmpFile);\n\n                return false;\n            }\n        }\n\n        @chmod($path, 0o666 & ~umask());\n\n        return true;\n    }\n\n    public function getPath(string $key): string\n    {\n        return $this->root.\\DIRECTORY_SEPARATOR.substr($key, 0, 2).\\DIRECTORY_SEPARATOR.substr($key, 2, 2).\\DIRECTORY_SEPARATOR.substr($key, 4, 2).\\DIRECTORY_SEPARATOR.substr($key, 6);\n    }\n\n    /**\n     * Generates a cache key for the given Request.\n     *\n     * This method should return a key that must only depend on a\n     * normalized version of the request URI.\n     *\n     * If the same URI can have more than one representation, based on some\n     * headers, use a Vary header to indicate them, and each representation will\n     * be stored independently under the same cache key.\n     */\n    protected function generateCacheKey(Request $request): string\n    {\n        $key = $request->getUri();\n\n        if ('QUERY' === $request->getMethod()) {\n            // add null byte to separate the URI from the body and avoid boundary collisions\n            // which could lead to cache poisoning\n            $key .= \"\\0\".$request->getContent();\n        }\n\n        return 'md'.hash('sha256', $key);\n    }\n\n    /**\n     * Returns a cache key for the given Request.\n     */\n    private function getCacheKey(Request $request): string\n    {\n        if (isset($this->keyCache[$request])) {\n            return $this->keyCache[$request];\n        }\n\n        return $this->keyCache[$request] = $this->generateCacheKey($request);\n    }\n\n    /**\n     * Persists the Request HTTP headers.\n     */\n    private function persistRequest(Request $request): array\n    {\n        return $request->headers->all();\n    }\n\n    /**\n     * Persists the Response HTTP headers.\n     */\n    private function persistResponse(Response $response): array\n    {\n        $headers = $response->headers->all();\n        $headers['X-Status'] = [$response->getStatusCode()];\n\n        return $headers;\n    }\n\n    /**\n     * Restores a Response from the HTTP headers and body.\n     */\n    private function restoreResponse(array $headers, ?string $path = null): ?Response\n    {\n        $status = $headers['X-Status'][0];\n        unset($headers['X-Status']);\n        $content = null;\n\n        if (null !== $path) {\n            $headers['X-Body-File'] = [$path];\n            unset($headers['x-body-file']);\n\n            if ($headers['X-Body-Eval'] ?? $headers['x-body-eval'] ?? false) {\n                $content = file_get_contents($path);\n                \\assert(HttpCache::BODY_EVAL_BOUNDARY_LENGTH === 24);\n                if (48 > \\strlen($content) || substr($content, -24) !== substr($content, 0, 24)) {\n                    return null;\n                }\n            }\n        }\n\n        return new Response($content, $status, $headers);\n    }\n}\n"
  },
  {
    "path": "HttpCache/StoreInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * This code is partially based on the Rack-Cache library by Ryan Tomayko,\n * which is released under the MIT license.\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\HttpCache;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\n\n/**\n * Interface implemented by HTTP cache stores.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface StoreInterface\n{\n    /**\n     * Locates a cached Response for the Request provided.\n     */\n    public function lookup(Request $request): ?Response;\n\n    /**\n     * Writes a cache entry to the store for the given Request and Response.\n     *\n     * Existing entries are read and any that match the response are removed. This\n     * method calls write with the new list of cache entries.\n     *\n     * @return string The key under which the response is stored\n     */\n    public function write(Request $request, Response $response): string;\n\n    /**\n     * Invalidates all cache entries that match the request.\n     */\n    public function invalidate(Request $request): void;\n\n    /**\n     * Locks the cache for a given Request.\n     *\n     * @return bool|string true if the lock is acquired, the path to the current lock otherwise\n     */\n    public function lock(Request $request): bool|string;\n\n    /**\n     * Releases the lock for the given Request.\n     *\n     * @return bool False if the lock file does not exist or cannot be unlocked, true otherwise\n     */\n    public function unlock(Request $request): bool;\n\n    /**\n     * Returns whether or not a lock exists.\n     *\n     * @return bool true if lock exists, false otherwise\n     */\n    public function isLocked(Request $request): bool;\n\n    /**\n     * Purges data for the given URL.\n     *\n     * @return bool true if the URL exists and has been purged, false otherwise\n     */\n    public function purge(string $url): bool;\n\n    /**\n     * Cleanups storage.\n     */\n    public function cleanup(): void;\n}\n"
  },
  {
    "path": "HttpCache/SubRequestHandler.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\HttpCache;\n\nuse Symfony\\Component\\HttpFoundation\\IpUtils;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nclass SubRequestHandler\n{\n    public static function handle(HttpKernelInterface $kernel, Request $request, int $type, bool $catch): Response\n    {\n        // save global state related to trusted headers and proxies\n        $trustedProxies = Request::getTrustedProxies();\n        $trustedHeaderSet = Request::getTrustedHeaderSet();\n\n        // remove untrusted values\n        $remoteAddr = $request->server->get('REMOTE_ADDR');\n        if (!$remoteAddr || !IpUtils::checkIp($remoteAddr, $trustedProxies)) {\n            $trustedHeaders = [\n                'FORWARDED' => $trustedHeaderSet & Request::HEADER_FORWARDED,\n                'X_FORWARDED_FOR' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_FOR,\n                'X_FORWARDED_HOST' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_HOST,\n                'X_FORWARDED_PROTO' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PROTO,\n                'X_FORWARDED_PORT' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PORT,\n                'X_FORWARDED_PREFIX' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PREFIX,\n            ];\n            foreach (array_filter($trustedHeaders) as $name => $key) {\n                $request->headers->remove($name);\n                $request->server->remove('HTTP_'.$name);\n            }\n        }\n\n        // compute trusted values, taking any trusted proxies into account\n        $trustedIps = [];\n        $trustedValues = [];\n        foreach (array_reverse($request->getClientIps()) as $ip) {\n            $trustedIps[] = $ip;\n            $trustedValues[] = \\sprintf('for=\"%s\"', $ip);\n        }\n        if ($ip !== $remoteAddr) {\n            $trustedIps[] = $remoteAddr;\n            $trustedValues[] = \\sprintf('for=\"%s\"', $remoteAddr);\n        }\n\n        // set trusted values, reusing as much as possible the global trusted settings\n        if (Request::HEADER_FORWARDED & $trustedHeaderSet) {\n            $trustedValues[0] .= \\sprintf(';host=\"%s\";proto=%s', $request->getHttpHost(), $request->getScheme());\n            $request->headers->set('Forwarded', $v = implode(', ', $trustedValues));\n            $request->server->set('HTTP_FORWARDED', $v);\n        }\n        if (Request::HEADER_X_FORWARDED_FOR & $trustedHeaderSet) {\n            $request->headers->set('X-Forwarded-For', $v = implode(', ', $trustedIps));\n            $request->server->set('HTTP_X_FORWARDED_FOR', $v);\n        } elseif (!(Request::HEADER_FORWARDED & $trustedHeaderSet)) {\n            Request::setTrustedProxies($trustedProxies, $trustedHeaderSet | Request::HEADER_X_FORWARDED_FOR);\n            $request->headers->set('X-Forwarded-For', $v = implode(', ', $trustedIps));\n            $request->server->set('HTTP_X_FORWARDED_FOR', $v);\n        }\n\n        // fix the client IP address by setting it to 127.0.0.1,\n        // which is the core responsibility of this method\n        $request->server->set('REMOTE_ADDR', '127.0.0.1');\n\n        // ensure 127.0.0.1 is set as trusted proxy\n        if (!IpUtils::checkIp('127.0.0.1', $trustedProxies)) {\n            Request::setTrustedProxies(array_merge($trustedProxies, ['127.0.0.1']), Request::getTrustedHeaderSet());\n        }\n\n        try {\n            return $kernel->handle($request, $type, $catch);\n        } finally {\n            // restore global state\n            Request::setTrustedProxies($trustedProxies, $trustedHeaderSet);\n        }\n    }\n}\n"
  },
  {
    "path": "HttpCache/SurrogateInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\HttpCache;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\n\ninterface SurrogateInterface\n{\n    /**\n     * Returns surrogate name.\n     */\n    public function getName(): string;\n\n    /**\n     * Returns a new cache strategy instance.\n     */\n    public function createCacheStrategy(): ResponseCacheStrategyInterface;\n\n    /**\n     * Checks that at least one surrogate has Surrogate capability.\n     */\n    public function hasSurrogateCapability(Request $request): bool;\n\n    /**\n     * Adds Surrogate-capability to the given Request.\n     */\n    public function addSurrogateCapability(Request $request): void;\n\n    /**\n     * Adds HTTP headers to specify that the Response needs to be parsed for Surrogate.\n     *\n     * This method only adds an Surrogate HTTP header if the Response has some Surrogate tags.\n     */\n    public function addSurrogateControl(Response $response): void;\n\n    /**\n     * Checks that the Response needs to be parsed for Surrogate tags.\n     */\n    public function needsParsing(Response $response): bool;\n\n    /**\n     * Renders a Surrogate tag.\n     *\n     * @param string|null $alt     An alternate URI\n     * @param string      $comment A comment to add as an esi:include tag\n     */\n    public function renderIncludeTag(string $uri, ?string $alt = null, bool $ignoreErrors = true, string $comment = ''): string;\n\n    /**\n     * Replaces a Response Surrogate tags with the included resource content.\n     */\n    public function process(Request $request, Response $response): Response;\n\n    /**\n     * Handles a Surrogate from the cache.\n     *\n     * @param string $alt An alternative URI\n     *\n     * @throws \\RuntimeException\n     * @throws \\Exception\n     */\n    public function handle(HttpCache $cache, string $uri, string $alt, bool $ignoreErrors): string;\n}\n"
  },
  {
    "path": "HttpClientKernel.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel;\n\nuse Symfony\\Component\\HttpClient\\HttpClient;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpFoundation\\ResponseHeaderBag;\nuse Symfony\\Component\\Mime\\Part\\AbstractPart;\nuse Symfony\\Component\\Mime\\Part\\DataPart;\nuse Symfony\\Component\\Mime\\Part\\Multipart\\FormDataPart;\nuse Symfony\\Component\\Mime\\Part\\TextPart;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\n\n// Help opcache.preload discover always-needed symbols\nclass_exists(ResponseHeaderBag::class);\n\n/**\n * An implementation of a Symfony HTTP kernel using a \"real\" HTTP client.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nfinal class HttpClientKernel implements HttpKernelInterface\n{\n    private HttpClientInterface $client;\n\n    public function __construct(?HttpClientInterface $client = null)\n    {\n        if (null === $client && !class_exists(HttpClient::class)) {\n            throw new \\LogicException(\\sprintf('You cannot use \"%s\" as the HttpClient component is not installed. Try running \"composer require symfony/http-client\".', __CLASS__));\n        }\n\n        $this->client = $client ?? HttpClient::create();\n    }\n\n    public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response\n    {\n        $headers = $this->getHeaders($request);\n        $body = '';\n        if (null !== $part = $this->getBody($request)) {\n            $headers = array_merge($headers, $part->getPreparedHeaders()->toArray());\n            $body = $part->bodyToIterable();\n        }\n        $response = $this->client->request($request->getMethod(), $request->getUri(), [\n            'headers' => $headers,\n            'body' => $body,\n        ] + $request->attributes->get('http_client_options', []));\n\n        $headers = new class($response->getHeaders(!$catch)) extends ResponseHeaderBag {\n            protected function computeCacheControlValue(): string\n            {\n                return $this->getCacheControlHeader(); // preserve the original value\n            }\n        };\n        $headers->remove('X-Body-File');\n        $headers->remove('X-Body-Eval');\n        $headers->remove('X-Content-Digest');\n\n        try {\n            return new Response($response->getContent(!$catch), $response->getStatusCode(), $headers);\n        } catch (\\TypeError) {\n            // BC with Symfony < 8.1\n            $response = new Response($response->getContent(!$catch), $response->getStatusCode());\n            $response->headers = $headers;\n\n            return $response;\n        }\n    }\n\n    private function getBody(Request $request): ?AbstractPart\n    {\n        if (\\in_array($request->getMethod(), ['GET', 'HEAD'], true)) {\n            return null;\n        }\n\n        if (!class_exists(AbstractPart::class)) {\n            throw new \\LogicException('You cannot pass non-empty bodies as the Mime component is not installed. Try running \"composer require symfony/mime\".');\n        }\n\n        if ($content = $request->getContent()) {\n            return new TextPart($content, 'utf-8', 'plain', '8bit');\n        }\n\n        $fields = $request->request->all();\n        foreach ($request->files->all() as $name => $file) {\n            $fields[$name] = DataPart::fromPath($file->getPathname(), $file->getClientOriginalName(), $file->getClientMimeType());\n        }\n\n        return new FormDataPart($fields);\n    }\n\n    private function getHeaders(Request $request): array\n    {\n        $headers = [];\n        foreach ($request->headers as $key => $value) {\n            $headers[$key] = $value;\n        }\n        $cookies = [];\n        foreach ($request->cookies->all() as $name => $value) {\n            $cookies[] = $name.'='.$value;\n        }\n        if ($cookies) {\n            $headers['cookie'] = implode('; ', $cookies);\n        }\n\n        return $headers;\n    }\n}\n"
  },
  {
    "path": "HttpKernel.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel;\n\nuse Symfony\\Component\\HttpFoundation\\Exception\\RequestExceptionInterface;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpFoundation\\StreamedResponse;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolverInterface;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsMetadata;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerMetadata;\nuse Symfony\\Component\\HttpKernel\\Event\\ExceptionEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\FinishRequestEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\RequestEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\TerminateEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ViewEvent;\nuse Symfony\\Component\\HttpKernel\\Exception\\BadRequestHttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\ControllerDoesNotReturnResponseException;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpExceptionInterface;\nuse Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;\nuse Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface;\n\n// Help opcache.preload discover always-needed symbols\nclass_exists(ControllerArgumentsEvent::class);\nclass_exists(ControllerArgumentsMetadata::class);\nclass_exists(ControllerEvent::class);\nclass_exists(ExceptionEvent::class);\nclass_exists(FinishRequestEvent::class);\nclass_exists(RequestEvent::class);\nclass_exists(ResponseEvent::class);\nclass_exists(TerminateEvent::class);\nclass_exists(ViewEvent::class);\nclass_exists(KernelEvents::class);\n\n/**\n * HttpKernel notifies events to convert a Request object to a Response one.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass HttpKernel implements HttpKernelInterface, TerminableInterface\n{\n    protected RequestStack $requestStack;\n    private ArgumentResolverInterface $argumentResolver;\n    private bool $terminating = false;\n\n    public function __construct(\n        protected EventDispatcherInterface $dispatcher,\n        protected ControllerResolverInterface $resolver,\n        ?RequestStack $requestStack = null,\n        ?ArgumentResolverInterface $argumentResolver = null,\n        private bool $handleAllThrowables = false,\n    ) {\n        $this->requestStack = $requestStack ?? new RequestStack();\n        $this->argumentResolver = $argumentResolver ?? new ArgumentResolver();\n    }\n\n    public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response\n    {\n        $request->headers->set('X-Php-Ob-Level', (string) ob_get_level());\n\n        $this->requestStack->push($request);\n        $response = null;\n        try {\n            return $response = $this->handleRaw($request, $type, $controllerMetadata);\n        } catch (\\Throwable $e) {\n            if ($e instanceof \\Error && !$this->handleAllThrowables) {\n                throw $e;\n            }\n\n            if ($e instanceof RequestExceptionInterface) {\n                $e = new BadRequestHttpException($e->getMessage(), $e);\n            }\n            if (false === $catch) {\n                $this->finishRequest($request, $type, $controllerMetadata);\n\n                throw $e;\n            }\n\n            return $response = $this->handleThrowable($e, $request, $type, $controllerMetadata);\n        } finally {\n            $this->requestStack->pop();\n\n            if ($response instanceof StreamedResponse && $callback = $response->getCallback()) {\n                $requestStack = $this->requestStack;\n\n                $response->setCallback(static function () use ($request, $callback, $requestStack) {\n                    $requestStack->push($request);\n                    try {\n                        $callback();\n                    } finally {\n                        $requestStack->pop();\n                    }\n                });\n            }\n        }\n    }\n\n    public function terminate(Request $request, Response $response): void\n    {\n        try {\n            $this->terminating = true;\n            $this->dispatcher->dispatch(new TerminateEvent($this, $request, $response), KernelEvents::TERMINATE);\n        } finally {\n            $this->terminating = false;\n        }\n    }\n\n    /**\n     * @internal\n     */\n    public function terminateWithException(\\Throwable $exception, ?Request $request = null): void\n    {\n        if (!$request ??= $this->requestStack->getMainRequest()) {\n            throw $exception;\n        }\n\n        if ($pop = $request !== $this->requestStack->getMainRequest()) {\n            $this->requestStack->push($request);\n        }\n\n        try {\n            $response = $this->handleThrowable($exception, $request, self::MAIN_REQUEST);\n        } finally {\n            if ($pop) {\n                $this->requestStack->pop();\n            }\n        }\n\n        $response->sendHeaders();\n        $response->sendContent();\n\n        $this->terminate($request, $response);\n    }\n\n    /**\n     * Handles a request to convert it to a response.\n     *\n     * Exceptions are not caught.\n     *\n     * @throws \\LogicException       If one of the listener does not behave as expected\n     * @throws NotFoundHttpException When controller cannot be found\n     */\n    private function handleRaw(Request $request, int $type = self::MAIN_REQUEST, ?ControllerMetadata &$controllerMetadata = null): Response\n    {\n        // request\n        $event = new RequestEvent($this, $request, $type);\n        $this->dispatcher->dispatch($event, KernelEvents::REQUEST);\n\n        if ($event->hasResponse()) {\n            return $this->filterResponse($event->getResponse(), $request, $type);\n        }\n\n        // load controller\n        if (false === $controller = $this->resolver->getController($request)) {\n            throw new NotFoundHttpException(\\sprintf('Unable to find the controller for path \"%s\". The route is wrongly configured.', $request->getPathInfo()));\n        }\n\n        $controllerEvent = $event = new ControllerEvent($this, $controller, $request, $type);\n        $controllerMetadata = new ControllerMetadata($event);\n        $this->dispatcher->dispatch($event, KernelEvents::CONTROLLER);\n        $controller = $event->getController();\n\n        // controller arguments\n        $arguments = $this->argumentResolver->getArguments($request, $controller, $event->getControllerReflector());\n\n        $event = new ControllerArgumentsEvent($this, $event, $arguments, $request, $type);\n        $controllerMetadata = new ControllerArgumentsMetadata($controllerEvent, $event);\n        $this->dispatcher->dispatch($event, KernelEvents::CONTROLLER_ARGUMENTS);\n        $controller = $event->getController();\n        $arguments = $event->getArguments();\n\n        // call controller\n        $response = $controller(...$arguments);\n\n        // view\n        if (!$response instanceof Response) {\n            $event = new ViewEvent($this, $request, $type, $response, $controllerMetadata);\n            $this->dispatcher->dispatch($event, KernelEvents::VIEW);\n\n            if ($event->hasResponse()) {\n                $response = $event->getResponse();\n            } else {\n                $msg = \\sprintf('The controller must return a \"Symfony\\Component\\HttpFoundation\\Response\" object but it returned %s.', $this->varToString($response));\n\n                // the user may have forgotten to return something\n                if (null === $response) {\n                    $msg .= ' Did you forget to add a return statement somewhere in your controller?';\n                }\n\n                throw new ControllerDoesNotReturnResponseException($msg, $controller, __FILE__, __LINE__ - 17);\n            }\n        }\n\n        return $this->filterResponse($response, $request, $type, $controllerMetadata);\n    }\n\n    /**\n     * Filters a response object.\n     *\n     * @throws \\RuntimeException if the passed object is not a Response instance\n     */\n    private function filterResponse(Response $response, Request $request, int $type, ?ControllerMetadata $controllerMetadata = null): Response\n    {\n        $event = new ResponseEvent($this, $request, $type, $response, $controllerMetadata);\n\n        $this->dispatcher->dispatch($event, KernelEvents::RESPONSE);\n\n        $this->finishRequest($request, $type, $controllerMetadata);\n\n        return $event->getResponse();\n    }\n\n    /**\n     * Publishes the finish request event, then pop the request from the stack.\n     *\n     * Note that the order of the operations is important here, otherwise\n     * operations such as {@link RequestStack::getParentRequest()} can lead to\n     * weird results.\n     */\n    private function finishRequest(Request $request, int $type, ?ControllerMetadata $controllerMetadata = null): void\n    {\n        $this->dispatcher->dispatch(new FinishRequestEvent($this, $request, $type, $controllerMetadata), KernelEvents::FINISH_REQUEST);\n    }\n\n    /**\n     * Handles a throwable by trying to convert it to a Response.\n     */\n    private function handleThrowable(\\Throwable $e, Request $request, int $type, ?ControllerMetadata $controllerMetadata = null): Response\n    {\n        $event = new ExceptionEvent($this, $request, $type, $e, isKernelTerminating: $this->terminating, controllerMetadata: $controllerMetadata);\n        $this->dispatcher->dispatch($event, KernelEvents::EXCEPTION);\n\n        // a listener might have replaced the exception\n        $e = $event->getThrowable();\n\n        if (!$event->hasResponse()) {\n            $this->finishRequest($request, $type, $controllerMetadata);\n\n            throw $e;\n        }\n\n        $response = $event->getResponse();\n\n        // the developer asked for a specific status code\n        if (!$event->isAllowingCustomResponseCode() && !$response->isClientError() && !$response->isServerError() && !$response->isRedirect()) {\n            // ensure that we actually have an error response\n            if ($e instanceof HttpExceptionInterface) {\n                // keep the HTTP status code and headers\n                $response->setStatusCode($e->getStatusCode());\n                $response->headers->add($e->getHeaders());\n            } else {\n                $response->setStatusCode(500);\n            }\n        }\n\n        try {\n            return $this->filterResponse($response, $request, $type, $controllerMetadata);\n        } catch (\\Throwable $e) {\n            if ($e instanceof \\Error && !$this->handleAllThrowables) {\n                throw $e;\n            }\n\n            return $response;\n        }\n    }\n\n    /**\n     * Returns a human-readable string for the specified variable.\n     */\n    private function varToString(mixed $var): string\n    {\n        if (\\is_object($var)) {\n            return \\sprintf('an object of type %s', $var::class);\n        }\n\n        if (\\is_array($var)) {\n            $a = [];\n            foreach ($var as $k => $v) {\n                $a[] = \\sprintf('%s => ...', $k);\n            }\n\n            return \\sprintf('an array ([%s])', mb_substr(implode(', ', $a), 0, 255));\n        }\n\n        if (\\is_resource($var)) {\n            return \\sprintf('a resource (%s)', get_resource_type($var));\n        }\n\n        if (null === $var) {\n            return 'null';\n        }\n\n        if (false === $var) {\n            return 'a boolean value (false)';\n        }\n\n        if (true === $var) {\n            return 'a boolean value (true)';\n        }\n\n        if (\\is_string($var)) {\n            return \\sprintf('a string (\"%s%s\")', mb_substr($var, 0, 255), mb_strlen($var) > 255 ? '...' : '');\n        }\n\n        if (is_numeric($var)) {\n            return \\sprintf('a number (%s)', (string) $var);\n        }\n\n        return (string) $var;\n    }\n}\n"
  },
  {
    "path": "HttpKernelBrowser.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel;\n\nuse Symfony\\Component\\BrowserKit\\AbstractBrowser;\nuse Symfony\\Component\\BrowserKit\\CookieJar;\nuse Symfony\\Component\\BrowserKit\\History;\nuse Symfony\\Component\\BrowserKit\\Request as DomRequest;\nuse Symfony\\Component\\BrowserKit\\Response as DomResponse;\nuse Symfony\\Component\\HttpFoundation\\File\\UploadedFile;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\n\n/**\n * Simulates a browser and makes requests to an HttpKernel instance.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @template-extends AbstractBrowser<Request, Response>\n */\nclass HttpKernelBrowser extends AbstractBrowser\n{\n    private bool $catchExceptions = true;\n\n    /**\n     * @param array $server The server parameters (equivalent of $_SERVER)\n     */\n    public function __construct(\n        protected HttpKernelInterface $kernel,\n        array $server = [],\n        ?History $history = null,\n        ?CookieJar $cookieJar = null,\n    ) {\n        // These class properties must be set before calling the parent constructor, as it may depend on it.\n        $this->followRedirects = false;\n\n        parent::__construct($server, $history, $cookieJar);\n    }\n\n    /**\n     * Sets whether to catch exceptions when the kernel is handling a request.\n     */\n    public function catchExceptions(bool $catchExceptions): void\n    {\n        $this->catchExceptions = $catchExceptions;\n    }\n\n    /**\n     * @param Request $request\n     */\n    protected function doRequest(object $request): Response\n    {\n        $response = $this->kernel->handle($request, HttpKernelInterface::MAIN_REQUEST, $this->catchExceptions);\n\n        if ($this->kernel instanceof TerminableInterface) {\n            $this->kernel->terminate($request, $response);\n        }\n\n        return $response;\n    }\n\n    /**\n     * @param Request $request\n     */\n    protected function getScript(object $request): string\n    {\n        $kernel = var_export(serialize($this->kernel), true);\n        $request = var_export(serialize($request), true);\n\n        $errorReporting = error_reporting();\n\n        $requires = '';\n        foreach (get_declared_classes() as $class) {\n            if (str_starts_with($class, 'ComposerAutoloaderInit')) {\n                $r = new \\ReflectionClass($class);\n                $file = \\dirname($r->getFileName(), 2).'/autoload.php';\n                if (file_exists($file)) {\n                    $requires .= 'require_once '.var_export($file, true).\";\\n\";\n                }\n            }\n        }\n\n        if (!$requires) {\n            throw new \\RuntimeException('Composer autoloader not found.');\n        }\n\n        $code = <<<EOF\n            <?php\n\n            error_reporting($errorReporting);\n\n            $requires\n\n            \\$kernel = unserialize($kernel);\n            \\$request = unserialize($request);\n            EOF;\n\n        return $code.$this->getHandleScript();\n    }\n\n    protected function getHandleScript(): string\n    {\n        return <<<'EOF'\n            $response = $kernel->handle($request);\n\n            if ($kernel instanceof Symfony\\Component\\HttpKernel\\TerminableInterface) {\n                $kernel->terminate($request, $response);\n            }\n\n            echo serialize($response);\n            EOF;\n    }\n\n    protected function filterRequest(DomRequest $request): Request\n    {\n        $httpRequest = Request::create($request->getUri(), $request->getMethod(), $request->getParameters(), $request->getCookies(), $request->getFiles(), $server = $request->getServer(), $request->getContent());\n        if (!isset($server['HTTP_ACCEPT'])) {\n            $httpRequest->headers->remove('Accept');\n        }\n\n        foreach ($this->filterFiles($httpRequest->files->all()) as $key => $value) {\n            $httpRequest->files->set($key, $value);\n        }\n\n        return $httpRequest;\n    }\n\n    /**\n     * Filters an array of files.\n     *\n     * This method created test instances of UploadedFile so that the move()\n     * method can be called on those instances.\n     *\n     * If the size of a file is greater than the allowed size (from php.ini) then\n     * an invalid UploadedFile is returned with an error set to UPLOAD_ERR_INI_SIZE.\n     *\n     * @see UploadedFile\n     */\n    protected function filterFiles(array $files): array\n    {\n        $filtered = [];\n        foreach ($files as $key => $value) {\n            if (\\is_array($value)) {\n                $filtered[$key] = $this->filterFiles($value);\n            } elseif ($value instanceof UploadedFile) {\n                if ($value->isValid() && $value->getSize() > UploadedFile::getMaxFilesize()) {\n                    $filtered[$key] = new UploadedFile(\n                        '',\n                        $value->getClientOriginalName(),\n                        $value->getClientMimeType(),\n                        \\UPLOAD_ERR_INI_SIZE,\n                        true\n                    );\n                } else {\n                    $filtered[$key] = new UploadedFile(\n                        $value->getPathname(),\n                        $value->getClientOriginalName(),\n                        $value->getClientMimeType(),\n                        $value->getError(),\n                        true\n                    );\n                }\n            }\n        }\n\n        return $filtered;\n    }\n\n    /**\n     * @param Response $response\n     */\n    protected function filterResponse(object $response): DomResponse\n    {\n        $content = '';\n        ob_start(static function ($chunk) use (&$content) {\n            $content .= $chunk;\n\n            return '';\n        });\n\n        try {\n            $response->sendContent();\n        } finally {\n            ob_end_clean();\n        }\n\n        return new DomResponse($content, $response->getStatusCode(), $response->headers->all());\n    }\n}\n"
  },
  {
    "path": "HttpKernelInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\n\n/**\n * HttpKernelInterface handles a Request to convert it to a Response.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface HttpKernelInterface\n{\n    public const MAIN_REQUEST = 1;\n    public const SUB_REQUEST = 2;\n\n    /**\n     * Handles a Request to convert it to a Response.\n     *\n     * When $catch is true, the implementation must catch all exceptions\n     * and do its best to convert them to a Response instance.\n     *\n     * @param int  $type  The type of the request\n     *                    (one of HttpKernelInterface::MAIN_REQUEST or HttpKernelInterface::SUB_REQUEST)\n     * @param bool $catch Whether to catch exceptions or not\n     *\n     * @throws \\Exception When an Exception occurs during processing\n     */\n    public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true): Response;\n}\n"
  },
  {
    "path": "Kernel.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel;\n\nuse Symfony\\Component\\Config\\ConfigCache;\nuse Symfony\\Component\\Config\\Loader\\DelegatingLoader;\nuse Symfony\\Component\\Config\\Loader\\LoaderResolver;\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\Compiler\\PassConfig;\nuse Symfony\\Component\\DependencyInjection\\Compiler\\RemoveBuildParametersPass;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\ContainerInterface;\nuse Symfony\\Component\\DependencyInjection\\Dumper\\PhpDumper;\nuse Symfony\\Component\\DependencyInjection\\Dumper\\Preloader;\nuse Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface;\nuse Symfony\\Component\\DependencyInjection\\Loader\\ClosureLoader;\nuse Symfony\\Component\\DependencyInjection\\Loader\\DirectoryLoader;\nuse Symfony\\Component\\DependencyInjection\\Loader\\GlobFileLoader;\nuse Symfony\\Component\\DependencyInjection\\Loader\\IniFileLoader;\nuse Symfony\\Component\\DependencyInjection\\Loader\\PhpFileLoader;\nuse Symfony\\Component\\DependencyInjection\\Loader\\YamlFileLoader;\nuse Symfony\\Component\\ErrorHandler\\DebugClassLoader;\nuse Symfony\\Component\\Filesystem\\Filesystem;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Bundle\\BundleInterface;\nuse Symfony\\Component\\HttpKernel\\CacheWarmer\\WarmableInterface;\nuse Symfony\\Component\\HttpKernel\\Config\\FileLocator;\nuse Symfony\\Component\\HttpKernel\\DependencyInjection\\MergeExtensionConfigurationPass;\n\n// Help opcache.preload discover always-needed symbols\nclass_exists(ConfigCache::class);\n\n/**\n * The Kernel is the heart of the Symfony system.\n *\n * It manages an environment made of bundles.\n *\n * Environment names must always start with a letter and\n * they must only contain letters and numbers.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nabstract class Kernel implements KernelInterface, RebootableInterface, TerminableInterface\n{\n    /**\n     * @var array<string, BundleInterface>\n     */\n    protected array $bundles = [];\n\n    protected ?ContainerInterface $container = null;\n    protected bool $booted = false;\n    protected ?float $startTime = null;\n\n    private string $projectDir;\n    private ?string $warmupDir = null;\n    private int $requestStackSize = 0;\n    private bool $resetServices = false;\n    private bool $handlingHttpCache = false;\n\n    /**\n     * @var array<string, bool>\n     */\n    private static array $freshCache = [];\n\n    public const VERSION = '8.1.0-DEV';\n    public const VERSION_ID = 80100;\n    public const MAJOR_VERSION = 8;\n    public const MINOR_VERSION = 1;\n    public const RELEASE_VERSION = 0;\n    public const EXTRA_VERSION = 'DEV';\n\n    public const END_OF_MAINTENANCE = '01/2027';\n    public const END_OF_LIFE = '01/2027';\n\n    public function __construct(\n        protected string $environment,\n        protected bool $debug,\n    ) {\n        if (!$environment) {\n            throw new \\InvalidArgumentException(\\sprintf('Invalid environment provided to \"%s\": the environment cannot be empty.', get_debug_type($this)));\n        }\n    }\n\n    public function __clone()\n    {\n        $this->booted = false;\n        $this->container = null;\n        $this->requestStackSize = 0;\n        $this->resetServices = false;\n        $this->handlingHttpCache = false;\n    }\n\n    public function boot(): void\n    {\n        if ($this->booted) {\n            if (!$this->requestStackSize && $this->resetServices) {\n                if ($this->container->has('services_resetter')) {\n                    $this->container->get('services_resetter')->reset();\n                }\n                $this->resetServices = false;\n                if ($this->debug) {\n                    $this->startTime = microtime(true);\n                }\n            }\n\n            return;\n        }\n\n        if (!$this->container) {\n            $this->preBoot();\n        }\n\n        foreach ($this->getBundles() as $bundle) {\n            $bundle->setContainer($this->container);\n            $bundle->boot();\n        }\n\n        $this->booted = true;\n    }\n\n    public function reboot(?string $warmupDir): void\n    {\n        $this->shutdown();\n        $this->warmupDir = $warmupDir;\n        $this->boot();\n    }\n\n    public function terminate(Request $request, Response $response): void\n    {\n        if (!$this->booted) {\n            return;\n        }\n\n        if ($this->getHttpKernel() instanceof TerminableInterface) {\n            $this->getHttpKernel()->terminate($request, $response);\n        }\n    }\n\n    public function shutdown(): void\n    {\n        if (!$this->booted) {\n            return;\n        }\n\n        $this->booted = false;\n\n        foreach ($this->getBundles() as $bundle) {\n            $bundle->shutdown();\n            $bundle->setContainer(null);\n        }\n\n        $this->container = null;\n        $this->requestStackSize = 0;\n        $this->resetServices = false;\n    }\n\n    public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response\n    {\n        if (!$this->container) {\n            $this->preBoot();\n        }\n\n        if (HttpKernelInterface::MAIN_REQUEST === $type && !$this->handlingHttpCache && $this->container->has('http_cache')) {\n            $this->handlingHttpCache = true;\n\n            try {\n                return $this->container->get('http_cache')->handle($request, $type, $catch);\n            } finally {\n                $this->handlingHttpCache = false;\n                $this->resetServices = true;\n            }\n        }\n\n        $this->boot();\n        ++$this->requestStackSize;\n        if (!$this->handlingHttpCache) {\n            $this->resetServices = true;\n        }\n\n        try {\n            return $this->getHttpKernel()->handle($request, $type, $catch);\n        } finally {\n            --$this->requestStackSize;\n        }\n    }\n\n    /**\n     * Gets an HTTP kernel from the container.\n     */\n    protected function getHttpKernel(): HttpKernelInterface\n    {\n        return $this->container->get('http_kernel');\n    }\n\n    public function getBundles(): array\n    {\n        return $this->bundles;\n    }\n\n    public function getBundle(string $name): BundleInterface\n    {\n        if (!isset($this->bundles[$name])) {\n            throw new \\InvalidArgumentException(\\sprintf('Bundle \"%s\" does not exist or it is not enabled. Maybe you forgot to add it in the \"registerBundles()\" method of your \"%s.php\" file?', $name, get_debug_type($this)));\n        }\n\n        return $this->bundles[$name];\n    }\n\n    public function locateResource(string $name): string\n    {\n        if ('@' !== $name[0]) {\n            throw new \\InvalidArgumentException(\\sprintf('A resource name must start with @ (\"%s\" given).', $name));\n        }\n\n        if (str_contains($name, '..')) {\n            throw new \\RuntimeException(\\sprintf('File name \"%s\" contains invalid characters (..).', $name));\n        }\n\n        $bundleName = substr($name, 1);\n        $path = '';\n        if (str_contains($bundleName, '/')) {\n            [$bundleName, $path] = explode('/', $bundleName, 2);\n        }\n\n        $bundle = $this->getBundle($bundleName);\n        if (file_exists($file = $bundle->getPath().'/'.$path)) {\n            return $file;\n        }\n\n        throw new \\InvalidArgumentException(\\sprintf('Unable to find file \"%s\".', $name));\n    }\n\n    public function getEnvironment(): string\n    {\n        return $this->environment;\n    }\n\n    public function isDebug(): bool\n    {\n        return $this->debug;\n    }\n\n    /**\n     * Gets the application root dir (path of the project's composer file).\n     */\n    public function getProjectDir(): string\n    {\n        if (!isset($this->projectDir)) {\n            $r = new \\ReflectionObject($this);\n\n            if (!is_file($dir = $r->getFileName())) {\n                throw new \\LogicException(\\sprintf('Cannot auto-detect project dir for kernel of class \"%s\".', $r->name));\n            }\n\n            $dir = $rootDir = \\dirname($dir);\n            while (!is_file($dir.'/composer.json')) {\n                if ($dir === \\dirname($dir)) {\n                    return $this->projectDir = $rootDir;\n                }\n                $dir = \\dirname($dir);\n            }\n            $this->projectDir = $dir;\n        }\n\n        return $this->projectDir;\n    }\n\n    public function getContainer(): ContainerInterface\n    {\n        if (!$this->container) {\n            throw new \\LogicException('Cannot retrieve the container from a non-booted kernel.');\n        }\n\n        return $this->container;\n    }\n\n    public function getStartTime(): float\n    {\n        return $this->debug && null !== $this->startTime ? $this->startTime : -\\INF;\n    }\n\n    public function getCacheDir(): string\n    {\n        return $this->getProjectDir().'/var/cache/'.$this->environment;\n    }\n\n    public function getBuildDir(): string\n    {\n        // Returns $this->getCacheDir() for backward compatibility\n        return $this->getCacheDir();\n    }\n\n    public function getShareDir(): ?string\n    {\n        // Returns $this->getCacheDir() for backward compatibility\n        return $this->getCacheDir();\n    }\n\n    public function getLogDir(): string\n    {\n        return $this->getProjectDir().'/var/log';\n    }\n\n    public function getCharset(): string\n    {\n        return 'UTF-8';\n    }\n\n    /**\n     * Initializes bundles.\n     *\n     * @throws \\LogicException if two bundles share a common name\n     */\n    protected function initializeBundles(): void\n    {\n        // init bundles\n        $this->bundles = [];\n        foreach ($this->registerBundles() as $bundle) {\n            $name = $bundle->getName();\n            if (isset($this->bundles[$name])) {\n                throw new \\LogicException(\\sprintf('Trying to register two bundles with the same name \"%s\".', $name));\n            }\n            $this->bundles[$name] = $bundle;\n        }\n    }\n\n    /**\n     * The extension point similar to the Bundle::build() method.\n     *\n     * Use this method to register compiler passes and manipulate the container during the building process.\n     */\n    protected function build(ContainerBuilder $container): void\n    {\n    }\n\n    /**\n     * Gets the container class.\n     *\n     * @throws \\InvalidArgumentException If the generated classname is invalid\n     */\n    protected function getContainerClass(): string\n    {\n        $class = static::class;\n        $class = str_contains($class, \"@anonymous\\0\") ? get_parent_class($class).str_replace('.', '_', ContainerBuilder::hash($class)) : $class;\n        $class = str_replace('\\\\', '_', $class).ucfirst($this->environment).($this->debug ? 'Debug' : '').'Container';\n\n        if (!preg_match('/^[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*$/', $class)) {\n            throw new \\InvalidArgumentException(\\sprintf('The environment \"%s\" contains invalid characters, it can only contain characters allowed in PHP class names.', $this->environment));\n        }\n\n        return $class;\n    }\n\n    /**\n     * Gets the container's base class.\n     *\n     * All names except Container must be fully qualified.\n     */\n    protected function getContainerBaseClass(): string\n    {\n        return 'Container';\n    }\n\n    /**\n     * Initializes the service container.\n     *\n     * The built version of the service container is used when fresh, otherwise the\n     * container is built.\n     */\n    protected function initializeContainer(): void\n    {\n        $class = $this->getContainerClass();\n        $buildDir = $this->warmupDir ?: $this->getBuildDir();\n        $skip = $_SERVER['SYMFONY_DISABLE_RESOURCE_TRACKING'] ?? '';\n        $skip = filter_var($skip, \\FILTER_VALIDATE_BOOLEAN, \\FILTER_NULL_ON_FAILURE) ?? explode(',', $skip);\n        $cache = new ConfigCache($buildDir.'/'.$class.'.php', $this->debug, null, \\is_array($skip) && ['*'] !== $skip ? $skip : ($skip ? [] : null));\n\n        $cachePath = $cache->getPath();\n\n        // Silence E_WARNING to ignore \"include\" failures - don't use \"@\" to prevent silencing fatal errors\n        $errorLevel = error_reporting();\n        error_reporting($errorLevel & ~\\E_WARNING);\n\n        try {\n            if (is_file($cachePath) && \\is_object($this->container = include $cachePath)\n                && (!$this->debug || (self::$freshCache[$cachePath] ?? $cache->isFresh()))\n            ) {\n                self::$freshCache[$cachePath] = true;\n                $this->container->set('kernel', $this);\n                error_reporting($errorLevel);\n\n                return;\n            }\n        } catch (\\Throwable $e) {\n        }\n\n        $oldContainer = \\is_object($this->container) ? new \\ReflectionClass($this->container) : $this->container = null;\n\n        try {\n            is_dir($buildDir) ?: mkdir($buildDir, 0o777, true);\n\n            if ($lock = fopen($cachePath.'.lock', 'w+')) {\n                if (!flock($lock, \\LOCK_EX | \\LOCK_NB, $wouldBlock) && !flock($lock, $wouldBlock ? \\LOCK_SH : \\LOCK_EX)) {\n                    fclose($lock);\n                    $lock = null;\n                } elseif (!is_file($cachePath) || !\\is_object($this->container = include $cachePath)) {\n                    $this->container = null;\n                } elseif (!$oldContainer || $this->container::class !== $oldContainer->name) {\n                    flock($lock, \\LOCK_UN);\n                    fclose($lock);\n                    $this->container->set('kernel', $this);\n\n                    return;\n                }\n            }\n        } catch (\\Throwable $e) {\n        } finally {\n            error_reporting($errorLevel);\n        }\n\n        if ($collectDeprecations = $this->debug && !\\defined('PHPUNIT_COMPOSER_INSTALL')) {\n            $collectedLogs = [];\n            $previousHandler = set_error_handler(static function ($type, $message, $file, $line) use (&$collectedLogs, &$previousHandler) {\n                if (\\E_USER_DEPRECATED !== $type && \\E_DEPRECATED !== $type) {\n                    return $previousHandler ? $previousHandler($type, $message, $file, $line) : false;\n                }\n\n                if (isset($collectedLogs[$message])) {\n                    ++$collectedLogs[$message]['count'];\n\n                    return null;\n                }\n\n                $backtrace = debug_backtrace(\\DEBUG_BACKTRACE_IGNORE_ARGS, 5);\n                // Clean the trace by removing first frames added by the error handler itself.\n                for ($i = 0; isset($backtrace[$i]); ++$i) {\n                    if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) {\n                        $backtrace = \\array_slice($backtrace, 1 + $i);\n                        break;\n                    }\n                }\n                for ($i = 0; isset($backtrace[$i]); ++$i) {\n                    if (!isset($backtrace[$i]['file'], $backtrace[$i]['line'], $backtrace[$i]['function'])) {\n                        continue;\n                    }\n                    if (!isset($backtrace[$i]['class']) && 'trigger_deprecation' === $backtrace[$i]['function']) {\n                        $file = $backtrace[$i]['file'];\n                        $line = $backtrace[$i]['line'];\n                        $backtrace = \\array_slice($backtrace, 1 + $i);\n                        break;\n                    }\n                }\n\n                // Remove frames added by DebugClassLoader.\n                for ($i = \\count($backtrace) - 2; 0 < $i; --$i) {\n                    if (DebugClassLoader::class === ($backtrace[$i]['class'] ?? null)) {\n                        $backtrace = [$backtrace[$i + 1]];\n                        break;\n                    }\n                }\n\n                $collectedLogs[$message] = [\n                    'type' => $type,\n                    'message' => $message,\n                    'file' => $file,\n                    'line' => $line,\n                    'trace' => [$backtrace[0]],\n                    'count' => 1,\n                ];\n\n                return null;\n            });\n        }\n\n        try {\n            $container = null;\n            $container = $this->buildContainer();\n            $container->compile();\n        } finally {\n            if ($collectDeprecations) {\n                restore_error_handler();\n\n                @file_put_contents($buildDir.'/'.$class.'Deprecations.log', serialize(array_values($collectedLogs)));\n                @file_put_contents($buildDir.'/'.$class.'Compiler.log', null !== $container ? implode(\"\\n\", $container->getCompiler()->getLog()) : '');\n            }\n        }\n\n        $this->dumpContainer($cache, $container, $class, $this->getContainerBaseClass());\n\n        if ($lock) {\n            flock($lock, \\LOCK_UN);\n            fclose($lock);\n        }\n\n        $this->container = require $cachePath;\n        $this->container->set('kernel', $this);\n\n        if ($oldContainer && $this->container::class !== $oldContainer->name) {\n            // Because concurrent requests might still be using them,\n            // old container files are not removed immediately,\n            // but on a next dump of the container.\n            static $legacyContainers = [];\n            $oldContainerDir = \\dirname($oldContainer->getFileName());\n            $legacyContainers[$oldContainerDir.'.legacy'] = true;\n            foreach (glob(\\dirname($oldContainerDir).\\DIRECTORY_SEPARATOR.'*.legacy', \\GLOB_NOSORT) as $legacyContainer) {\n                if (!isset($legacyContainers[$legacyContainer]) && @unlink($legacyContainer)) {\n                    (new Filesystem())->remove(substr($legacyContainer, 0, -7));\n                }\n            }\n\n            touch($oldContainerDir.'.legacy');\n        }\n\n        $buildDir = $this->container->getParameter('kernel.build_dir');\n        $cacheDir = $this->container->getParameter('kernel.cache_dir');\n        $preload = $this instanceof WarmableInterface ? $this->warmUp($cacheDir, $buildDir) : [];\n\n        if ($this->container->has('cache_warmer')) {\n            $cacheWarmer = $this->container->get('cache_warmer');\n\n            if ($cacheDir !== $buildDir) {\n                $cacheWarmer->enableOptionalWarmers();\n            }\n\n            $preload = array_merge($preload, $cacheWarmer->warmUp($cacheDir, $buildDir));\n        }\n\n        if ($preload && file_exists($preloadFile = $buildDir.'/'.$class.'.preload.php')) {\n            Preloader::append($preloadFile, $preload);\n        }\n    }\n\n    /**\n     * Returns the kernel parameters.\n     *\n     * @return array<string, array|bool|string|int|float|\\UnitEnum|null>\n     */\n    protected function getKernelParameters(): array\n    {\n        $bundles = [];\n        $bundlesMetadata = [];\n\n        foreach ($this->bundles as $name => $bundle) {\n            $bundles[$name] = $bundle::class;\n            $bundlesMetadata[$name] = [\n                'path' => $bundle->getPath(),\n                'namespace' => $bundle->getNamespace(),\n            ];\n        }\n\n        return [\n            'kernel.project_dir' => realpath($this->getProjectDir()) ?: $this->getProjectDir(),\n            'kernel.environment' => $this->environment,\n            'kernel.runtime_environment' => '%env(default:kernel.environment:APP_RUNTIME_ENV)%',\n            'kernel.runtime_mode' => '%env(query_string:default:container.runtime_mode:APP_RUNTIME_MODE)%',\n            'kernel.runtime_mode.web' => '%env(bool:default::key:web:default:kernel.runtime_mode:)%',\n            'kernel.runtime_mode.cli' => '%env(not:default:kernel.runtime_mode.web:)%',\n            'kernel.runtime_mode.worker' => '%env(bool:default::key:worker:default:kernel.runtime_mode:)%',\n            'kernel.debug' => $this->debug,\n            'kernel.build_dir' => realpath($dir = $this->warmupDir ?: $this->getBuildDir()) ?: $dir,\n            'kernel.cache_dir' => realpath($dir = ($this->getCacheDir() === $this->getBuildDir() ? ($this->warmupDir ?: $this->getCacheDir()) : $this->getCacheDir())) ?: $dir,\n            'kernel.logs_dir' => realpath($dir = $this->getLogDir()) ?: $dir,\n            'kernel.bundles' => $bundles,\n            'kernel.bundles_metadata' => $bundlesMetadata,\n            'kernel.charset' => $this->getCharset(),\n            'kernel.container_class' => $this->getContainerClass(),\n        ] + (null !== ($dir = $this->getShareDir()) ? ['kernel.share_dir' => realpath($dir) ?: $dir] : []);\n    }\n\n    /**\n     * Builds the service container.\n     *\n     * @throws \\RuntimeException\n     */\n    protected function buildContainer(): ContainerBuilder\n    {\n        foreach (['cache' => $this->getCacheDir(), 'build' => $this->warmupDir ?: $this->getBuildDir()] as $name => $dir) {\n            if (!is_dir($dir)) {\n                if (!@mkdir($dir, 0o777, true) && !is_dir($dir)) {\n                    throw new \\RuntimeException(\\sprintf('Unable to create the \"%s\" directory (%s).', $name, $dir));\n                }\n            } elseif (!is_writable($dir)) {\n                throw new \\RuntimeException(\\sprintf('Unable to write in the \"%s\" directory (%s).', $name, $dir));\n            }\n        }\n\n        $container = $this->getContainerBuilder();\n        $container->addObjectResource($this);\n        $this->prepareContainer($container);\n        $this->registerContainerConfiguration($this->getContainerLoader($container));\n\n        return $container;\n    }\n\n    /**\n     * Prepares the ContainerBuilder before it is compiled.\n     */\n    protected function prepareContainer(ContainerBuilder $container): void\n    {\n        $extensions = [];\n        foreach ($this->bundles as $bundle) {\n            if ($extension = $bundle->getContainerExtension()) {\n                $container->registerExtension($extension);\n            }\n\n            if ($this->debug) {\n                $container->addObjectResource($bundle);\n            }\n\n            if ($bundle instanceof CompilerPassInterface) {\n                $container->addCompilerPass($bundle, PassConfig::TYPE_BEFORE_OPTIMIZATION, -10000);\n            }\n        }\n\n        foreach ($this->bundles as $bundle) {\n            $bundle->build($container);\n        }\n\n        $this->build($container);\n\n        foreach ($container->getExtensions() as $extension) {\n            $extensions[] = $extension->getAlias();\n        }\n\n        // ensure these extensions are implicitly loaded\n        $container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions));\n    }\n\n    /**\n     * Gets a new ContainerBuilder instance used to build the service container.\n     */\n    protected function getContainerBuilder(): ContainerBuilder\n    {\n        $container = new ContainerBuilder();\n        $container->getParameterBag()->add($this->getKernelParameters());\n\n        if ($this instanceof ExtensionInterface) {\n            $container->registerExtension($this);\n        }\n        if ($this instanceof CompilerPassInterface) {\n            $container->addCompilerPass($this, PassConfig::TYPE_BEFORE_OPTIMIZATION, -10000);\n        }\n\n        return $container;\n    }\n\n    /**\n     * Dumps the service container to PHP code in the cache.\n     *\n     * @param string $class     The name of the class to generate\n     * @param string $baseClass The name of the container's base class\n     */\n    protected function dumpContainer(ConfigCache $cache, ContainerBuilder $container, string $class, string $baseClass): void\n    {\n        // cache the container\n        $dumper = new PhpDumper($container);\n\n        $buildParameters = [];\n        foreach ($container->getCompilerPassConfig()->getPasses() as $pass) {\n            if ($pass instanceof RemoveBuildParametersPass) {\n                $buildParameters = array_merge($buildParameters, $pass->getRemovedParameters());\n            }\n        }\n\n        if (null === $buildTime = filter_var($_SERVER['SOURCE_DATE_EPOCH'] ?? null, \\FILTER_VALIDATE_INT, \\FILTER_NULL_ON_FAILURE)) {\n            $buildTime = time();\n        }\n\n        $content = $dumper->dump([\n            'class' => $class,\n            'base_class' => $baseClass,\n            'file' => $cache->getPath(),\n            'as_files' => true,\n            'debug' => $this->debug,\n            'inline_factories' => $buildParameters['.container.dumper.inline_factories'] ?? false,\n            'inline_class_loader' => $buildParameters['.container.dumper.inline_class_loader'] ?? $this->debug,\n            'build_time' => $container->hasParameter('kernel.container_build_time') ? $container->getParameter('kernel.container_build_time') : $buildTime,\n            'preload_classes' => array_map('get_class', $this->bundles),\n        ]);\n\n        $rootCode = array_pop($content);\n        $dir = \\dirname($cache->getPath()).'/';\n        $fs = new Filesystem();\n\n        foreach ($content as $file => $code) {\n            $fs->dumpFile($dir.$file, $code);\n            @chmod($dir.$file, 0o666 & ~umask());\n        }\n        $legacyFile = \\dirname($dir.key($content)).'.legacy';\n        if (is_file($legacyFile)) {\n            @unlink($legacyFile);\n        }\n\n        $cache->write($rootCode, $container->getResources());\n    }\n\n    /**\n     * Returns a loader for the container.\n     */\n    protected function getContainerLoader(ContainerInterface $container): DelegatingLoader\n    {\n        $env = $this->getEnvironment();\n        $locator = new FileLocator($this);\n        $resolver = new LoaderResolver([\n            new YamlFileLoader($container, $locator, $env),\n            new IniFileLoader($container, $locator, $env),\n            new PhpFileLoader($container, $locator, $env),\n            new GlobFileLoader($container, $locator, $env),\n            new DirectoryLoader($container, $locator, $env),\n            new ClosureLoader($container, $env),\n        ]);\n\n        return new DelegatingLoader($resolver);\n    }\n\n    private function preBoot(): ContainerInterface\n    {\n        if ($this->debug) {\n            $this->startTime = microtime(true);\n        }\n        if ($this->debug && !isset($_ENV['SHELL_VERBOSITY']) && !isset($_SERVER['SHELL_VERBOSITY'])) {\n            if (\\function_exists('putenv')) {\n                putenv('SHELL_VERBOSITY=3');\n            }\n            $_ENV['SHELL_VERBOSITY'] = 3;\n            $_SERVER['SHELL_VERBOSITY'] = 3;\n        }\n\n        $this->initializeBundles();\n        $this->initializeContainer();\n\n        $container = $this->container;\n\n        if ($container->hasParameter('kernel.trusted_hosts') && $trustedHosts = $container->getParameter('kernel.trusted_hosts')) {\n            Request::setTrustedHosts(\\is_array($trustedHosts) ? $trustedHosts : preg_split('/\\s*+,\\s*+(?![^{]*})/', $trustedHosts));\n        }\n\n        if ($container->hasParameter('kernel.trusted_proxies') && $container->hasParameter('kernel.trusted_headers') && $trustedProxies = $container->getParameter('kernel.trusted_proxies')) {\n            $trustedHeaders = $container->getParameter('kernel.trusted_headers');\n\n            if (\\is_string($trustedHeaders)) {\n                $trustedHeaders = array_map('trim', explode(',', $trustedHeaders));\n            }\n\n            if (\\is_array($trustedHeaders)) {\n                $trustedHeaderSet = 0;\n\n                foreach ($trustedHeaders as $header) {\n                    if (!\\defined($const = Request::class.'::HEADER_'.strtr(strtoupper($header), '-', '_'))) {\n                        throw new \\InvalidArgumentException(\\sprintf('The trusted header \"%s\" is not supported.', $header));\n                    }\n                    $trustedHeaderSet |= \\constant($const);\n                }\n            } else {\n                $trustedHeaderSet = $trustedHeaders ?? (Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO);\n            }\n\n            Request::setTrustedProxies(\\is_array($trustedProxies) ? $trustedProxies : array_map('trim', explode(',', $trustedProxies)), $trustedHeaderSet);\n        }\n\n        return $container;\n    }\n\n    public function __serialize(): array\n    {\n        return [\n            'environment' => $this->environment,\n            'debug' => $this->debug,\n        ];\n    }\n\n    public function __unserialize(array $data): void\n    {\n        $environment = $data['environment'] ?? $data[\"\\0*\\0environment\"];\n        $debug = $data['debug'] ?? $data[\"\\0*\\0debug\"];\n\n        if (\\is_object($environment) || \\is_object($debug)) {\n            throw new \\BadMethodCallException('Cannot unserialize '.__CLASS__);\n        }\n\n        $this->environment = $environment;\n        $this->debug = $debug;\n\n        $this->__construct($environment, $debug);\n    }\n}\n"
  },
  {
    "path": "KernelEvents.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel;\n\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ExceptionEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\FinishRequestEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\RequestEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\TerminateEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ViewEvent;\n\n/**\n * Contains all events thrown in the HttpKernel component.\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nfinal class KernelEvents\n{\n    /**\n     * The REQUEST event occurs at the very beginning of request\n     * dispatching.\n     *\n     * This event allows you to create a response for a request before any\n     * other code in the framework is executed.\n     *\n     * @Event(\"Symfony\\Component\\HttpKernel\\Event\\RequestEvent\")\n     */\n    public const REQUEST = 'kernel.request';\n\n    /**\n     * The EXCEPTION event occurs when an uncaught exception appears.\n     *\n     * This event allows you to create a response for a thrown exception or\n     * to modify the thrown exception.\n     *\n     * @Event(\"Symfony\\Component\\HttpKernel\\Event\\ExceptionEvent\")\n     */\n    public const EXCEPTION = 'kernel.exception';\n\n    /**\n     * The CONTROLLER event occurs once a controller was found for\n     * handling a request.\n     *\n     * This event allows you to change the controller that will handle the\n     * request.\n     *\n     * @Event(\"Symfony\\Component\\HttpKernel\\Event\\ControllerEvent\")\n     */\n    public const CONTROLLER = 'kernel.controller';\n\n    /**\n     * The CONTROLLER_ARGUMENTS event occurs once controller arguments have been resolved.\n     *\n     * This event allows you to change the arguments that will be passed to\n     * the controller.\n     *\n     * @Event(\"Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsEvent\")\n     */\n    public const CONTROLLER_ARGUMENTS = 'kernel.controller_arguments';\n\n    /**\n     * The VIEW event occurs when the return value of a controller\n     * is not a Response instance.\n     *\n     * This event allows you to create a response for the return value of the\n     * controller.\n     *\n     * @Event(\"Symfony\\Component\\HttpKernel\\Event\\ViewEvent\")\n     */\n    public const VIEW = 'kernel.view';\n\n    /**\n     * The RESPONSE event occurs once a response was created for\n     * replying to a request.\n     *\n     * This event allows you to modify or replace the response that will be\n     * replied.\n     *\n     * @Event(\"Symfony\\Component\\HttpKernel\\Event\\ResponseEvent\")\n     */\n    public const RESPONSE = 'kernel.response';\n\n    /**\n     * The FINISH_REQUEST event occurs when a response was generated for a request.\n     *\n     * This event allows you to reset the global and environmental state of\n     * the application, when it was changed during the request.\n     *\n     * @Event(\"Symfony\\Component\\HttpKernel\\Event\\FinishRequestEvent\")\n     */\n    public const FINISH_REQUEST = 'kernel.finish_request';\n\n    /**\n     * The TERMINATE event occurs once a response was sent.\n     *\n     * This event allows you to run expensive post-response jobs.\n     *\n     * @Event(\"Symfony\\Component\\HttpKernel\\Event\\TerminateEvent\")\n     */\n    public const TERMINATE = 'kernel.terminate';\n\n    /**\n     * Event aliases.\n     *\n     * These aliases can be consumed by RegisterListenersPass.\n     */\n    public const ALIASES = [\n        ControllerArgumentsEvent::class => self::CONTROLLER_ARGUMENTS,\n        ControllerEvent::class => self::CONTROLLER,\n        ResponseEvent::class => self::RESPONSE,\n        FinishRequestEvent::class => self::FINISH_REQUEST,\n        RequestEvent::class => self::REQUEST,\n        ViewEvent::class => self::VIEW,\n        ExceptionEvent::class => self::EXCEPTION,\n        TerminateEvent::class => self::TERMINATE,\n    ];\n}\n"
  },
  {
    "path": "KernelInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel;\n\nuse Symfony\\Component\\Config\\Loader\\LoaderInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerInterface;\nuse Symfony\\Component\\HttpKernel\\Bundle\\BundleInterface;\n\n/**\n * The Kernel is the heart of the Symfony system.\n *\n * It manages an environment made of application kernel and bundles.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface KernelInterface extends HttpKernelInterface\n{\n    /**\n     * Returns an array of bundles to register.\n     *\n     * @return iterable<mixed, BundleInterface>\n     */\n    public function registerBundles(): iterable;\n\n    /**\n     * Loads the container configuration.\n     */\n    public function registerContainerConfiguration(LoaderInterface $loader): void;\n\n    /**\n     * Boots the current kernel.\n     */\n    public function boot(): void;\n\n    /**\n     * Shutdowns the kernel.\n     *\n     * This method is mainly useful when doing functional testing.\n     */\n    public function shutdown(): void;\n\n    /**\n     * Gets the registered bundle instances.\n     *\n     * @return array<string, BundleInterface>\n     */\n    public function getBundles(): array;\n\n    /**\n     * Returns a bundle.\n     *\n     * @throws \\InvalidArgumentException when the bundle is not enabled\n     */\n    public function getBundle(string $name): BundleInterface;\n\n    /**\n     * Returns the file path for a given bundle resource.\n     *\n     * A Resource can be a file or a directory.\n     *\n     * The resource name must follow the following pattern:\n     *\n     *     \"@BundleName/path/to/a/file.something\"\n     *\n     * where BundleName is the name of the bundle\n     * and the remaining part is the relative path in the bundle.\n     *\n     * @throws \\InvalidArgumentException if the file cannot be found or the name is not valid\n     * @throws \\RuntimeException         if the name contains invalid/unsafe characters\n     */\n    public function locateResource(string $name): string;\n\n    /**\n     * Gets the environment.\n     */\n    public function getEnvironment(): string;\n\n    /**\n     * Checks if debug mode is enabled.\n     */\n    public function isDebug(): bool;\n\n    /**\n     * Gets the project dir (path of the project's composer file).\n     */\n    public function getProjectDir(): string;\n\n    /**\n     * Gets the current container.\n     */\n    public function getContainer(): ContainerInterface;\n\n    /**\n     * Gets the request start time (not available if debug is disabled).\n     */\n    public function getStartTime(): float;\n\n    /**\n     * Gets the cache directory.\n     *\n     * This directory should be used for caches that are written at runtime.\n     * For caches and artifacts that can be warmed at compile-time and deployed as read-only,\n     * use the \"build directory\" returned by the {@see getBuildDir()} method.\n     */\n    public function getCacheDir(): string;\n\n    /**\n     * Returns the build directory.\n     *\n     * This directory should be used to store build artifacts, and can be read-only at runtime.\n     * System caches written at runtime should be stored in the \"cache directory\" ({@see KernelInterface::getCacheDir()}).\n     * Application caches that are shared between all front-end servers should be stored\n     * in the \"share directory\" ({@see KernelInterface::getShareDir()}).\n     */\n    public function getBuildDir(): string;\n\n    /**\n     * Returns the share directory.\n     *\n     * This directory should be used to store data that is shared between all front-end servers.\n     * This typically fits application caches.\n     */\n    public function getShareDir(): ?string;\n\n    /**\n     * Gets the log directory.\n     */\n    public function getLogDir(): string;\n\n    /**\n     * Gets the charset of the application.\n     */\n    public function getCharset(): string;\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2004-present Fabien Potencier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "Log/DebugLoggerConfigurator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Log;\n\nuse Monolog\\Logger;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass DebugLoggerConfigurator\n{\n    private ?object $processor = null;\n\n    public function __construct(callable $processor, ?bool $enable = null)\n    {\n        if ($enable ?? !\\in_array(\\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true)) {\n            $this->processor = \\is_object($processor) ? $processor : $processor(...);\n        }\n    }\n\n    public function pushDebugLogger(Logger $logger): void\n    {\n        if ($this->processor) {\n            $logger->pushProcessor($this->processor);\n        }\n    }\n\n    public static function getDebugLogger(mixed $logger): ?DebugLoggerInterface\n    {\n        if ($logger instanceof DebugLoggerInterface) {\n            return $logger;\n        }\n\n        if (!$logger instanceof Logger) {\n            return null;\n        }\n\n        foreach ($logger->getProcessors() as $processor) {\n            if ($processor instanceof DebugLoggerInterface) {\n                return $processor;\n            }\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "Log/DebugLoggerInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Log;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\n\n/**\n * DebugLoggerInterface.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface DebugLoggerInterface\n{\n    /**\n     * Returns an array of logs.\n     *\n     * @return array<array{\n     *     channel: ?string,\n     *     context: array<string, mixed>,\n     *     message: string,\n     *     priority: int,\n     *     priorityName: string,\n     *     timestamp: int,\n     *     timestamp_rfc3339: string,\n     * }>\n     */\n    public function getLogs(?Request $request = null): array;\n\n    /**\n     * Returns the number of errors.\n     */\n    public function countErrors(?Request $request = null): int;\n\n    /**\n     * Removes all log records.\n     */\n    public function clear(): void;\n}\n"
  },
  {
    "path": "Log/Logger.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Log;\n\nuse Psr\\Log\\AbstractLogger;\nuse Psr\\Log\\InvalidArgumentException;\nuse Psr\\Log\\LogLevel;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\n\n/**\n * Minimalist PSR-3 logger designed to write in stderr or any other stream.\n *\n * @author Kévin Dunglas <dunglas@gmail.com>\n */\nclass Logger extends AbstractLogger implements DebugLoggerInterface\n{\n    private const LEVELS = [\n        LogLevel::DEBUG => 0,\n        LogLevel::INFO => 1,\n        LogLevel::NOTICE => 2,\n        LogLevel::WARNING => 3,\n        LogLevel::ERROR => 4,\n        LogLevel::CRITICAL => 5,\n        LogLevel::ALERT => 6,\n        LogLevel::EMERGENCY => 7,\n    ];\n    private const PRIORITIES = [\n        LogLevel::DEBUG => 100,\n        LogLevel::INFO => 200,\n        LogLevel::NOTICE => 250,\n        LogLevel::WARNING => 300,\n        LogLevel::ERROR => 400,\n        LogLevel::CRITICAL => 500,\n        LogLevel::ALERT => 550,\n        LogLevel::EMERGENCY => 600,\n    ];\n\n    private int $minLevelIndex;\n    private \\Closure $formatter;\n    private bool $debug = false;\n    private array $logs = [];\n    private array $errorCount = [];\n\n    /** @var resource|null */\n    private $handle;\n\n    /**\n     * @param string|resource|null $output\n     */\n    public function __construct(?string $minLevel = null, $output = null, ?callable $formatter = null, private readonly ?RequestStack $requestStack = null, bool $debug = false)\n    {\n        $minLevel ??= match ((int) ($_ENV['SHELL_VERBOSITY'] ?? $_SERVER['SHELL_VERBOSITY'] ?? 0)) {\n            -1 => LogLevel::ERROR,\n            1 => LogLevel::NOTICE,\n            2 => LogLevel::INFO,\n            3 => LogLevel::DEBUG,\n            default => null === $output || 'php://stdout' === $output || 'php://stderr' === $output ? LogLevel::ERROR : LogLevel::WARNING,\n        };\n\n        if (!isset(self::LEVELS[$minLevel])) {\n            throw new InvalidArgumentException(\\sprintf('The log level \"%s\" does not exist.', $minLevel));\n        }\n\n        $this->minLevelIndex = self::LEVELS[$minLevel];\n        $this->formatter = null !== $formatter ? $formatter(...) : $this->format(...);\n        if ($output && false === $this->handle = \\is_string($output) ? @fopen($output, 'a') : $output) {\n            throw new InvalidArgumentException(\\sprintf('Unable to open \"%s\".', $output));\n        }\n        $this->debug = $debug;\n    }\n\n    public function enableDebug(): void\n    {\n        $this->debug = true;\n    }\n\n    public function log($level, $message, array $context = []): void\n    {\n        if (!isset(self::LEVELS[$level])) {\n            throw new InvalidArgumentException(\\sprintf('The log level \"%s\" does not exist.', $level));\n        }\n\n        if (self::LEVELS[$level] < $this->minLevelIndex) {\n            return;\n        }\n\n        $formatter = $this->formatter;\n        if ($this->handle) {\n            @fwrite($this->handle, $formatter($level, $message, $context).\\PHP_EOL);\n        } else {\n            error_log($formatter($level, $message, $context, false));\n        }\n\n        if ($this->debug && $this->requestStack) {\n            $this->record($level, $message, $context);\n        }\n    }\n\n    public function getLogs(?Request $request = null): array\n    {\n        if ($request) {\n            return $this->logs[spl_object_id($request)] ?? [];\n        }\n\n        return array_merge(...array_values($this->logs));\n    }\n\n    public function countErrors(?Request $request = null): int\n    {\n        if ($request) {\n            return $this->errorCount[spl_object_id($request)] ?? 0;\n        }\n\n        return array_sum($this->errorCount);\n    }\n\n    public function clear(): void\n    {\n        $this->logs = [];\n        $this->errorCount = [];\n    }\n\n    private function format(string $level, string $message, array $context, bool $prefixDate = true): string\n    {\n        if (str_contains($message, '{')) {\n            $replacements = [];\n            foreach ($context as $key => $val) {\n                if (null === $val || \\is_scalar($val) || $val instanceof \\Stringable) {\n                    $replacements[\"{{$key}}\"] = $val;\n                } elseif ($val instanceof \\DateTimeInterface) {\n                    $replacements[\"{{$key}}\"] = $val->format(\\DateTimeInterface::RFC3339);\n                } elseif (\\is_object($val)) {\n                    $replacements[\"{{$key}}\"] = '[object '.$val::class.']';\n                } else {\n                    $replacements[\"{{$key}}\"] = '['.\\gettype($val).']';\n                }\n            }\n\n            $message = strtr($message, $replacements);\n        }\n\n        $log = \\sprintf('[%s] %s', $level, $message);\n        if ($prefixDate) {\n            $log = date(\\DateTimeInterface::RFC3339).' '.$log;\n        }\n\n        return $log;\n    }\n\n    private function record($level, $message, array $context): void\n    {\n        $request = $this->requestStack->getCurrentRequest();\n        $key = $request ? spl_object_id($request) : '';\n\n        $this->logs[$key][] = [\n            'channel' => null,\n            'context' => $context,\n            'message' => $message,\n            'priority' => self::PRIORITIES[$level],\n            'priorityName' => $level,\n            'timestamp' => time(),\n            'timestamp_rfc3339' => date(\\DATE_RFC3339_EXTENDED),\n        ];\n\n        $this->errorCount[$key] ??= 0;\n        switch ($level) {\n            case LogLevel::ERROR:\n            case LogLevel::CRITICAL:\n            case LogLevel::ALERT:\n            case LogLevel::EMERGENCY:\n                ++$this->errorCount[$key];\n        }\n    }\n}\n"
  },
  {
    "path": "Profiler/FileProfilerStorage.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Profiler;\n\n/**\n * Storage for profiler using files.\n *\n * @author Alexandre Salomé <alexandre.salome@gmail.com>\n */\nclass FileProfilerStorage implements ProfilerStorageInterface\n{\n    /**\n     * Folder where profiler data are stored.\n     */\n    private string $folder;\n\n    /**\n     * Constructs the file storage using a \"dsn-like\" path.\n     *\n     * Example : \"file:/path/to/the/storage/folder\"\n     *\n     * @throws \\RuntimeException\n     */\n    public function __construct(string $dsn)\n    {\n        if (!str_starts_with($dsn, 'file:')) {\n            throw new \\RuntimeException(\\sprintf('Please check your configuration. You are trying to use FileStorage with an invalid dsn \"%s\". The expected format is \"file:/path/to/the/storage/folder\".', $dsn));\n        }\n        $this->folder = substr($dsn, 5);\n\n        if (!is_dir($this->folder) && false === @mkdir($this->folder, 0o777, true) && !is_dir($this->folder)) {\n            throw new \\RuntimeException(\\sprintf('Unable to create the storage directory (%s).', $this->folder));\n        }\n    }\n\n    public function find(?string $ip, ?string $url, ?int $limit, ?string $method, ?int $start = null, ?int $end = null, ?string $statusCode = null, ?\\Closure $filter = null): array\n    {\n        $file = $this->getIndexFilename();\n\n        if (!file_exists($file)) {\n            return [];\n        }\n\n        $file = fopen($file, 'r');\n        fseek($file, 0, \\SEEK_END);\n\n        $result = [];\n        while (\\count($result) < $limit && $line = $this->readLineFromFile($file)) {\n            $values = str_getcsv($line, ',', '\"', '\\\\');\n\n            if (7 > \\count($values)) {\n                // skip invalid lines\n                continue;\n            }\n\n            [$csvToken, $csvIp, $csvMethod, $csvUrl, $csvTime, $csvParent, $csvStatusCode, $csvVirtualType, $csvHasErrors] = $values + [7 => null, 8 => null];\n            $csvTime = (int) $csvTime;\n\n            $urlFilter = false;\n            if ($url) {\n                $urlFilter = str_starts_with($url, '!') ? str_contains($csvUrl, substr($url, 1)) : !str_contains($csvUrl, $url);\n            }\n\n            if ($ip && !str_contains($csvIp, $ip) || $urlFilter || $method && !str_contains($csvMethod, $method) || $statusCode && !str_contains($csvStatusCode, $statusCode)) {\n                continue;\n            }\n\n            if ($start && $csvTime < $start) {\n                continue;\n            }\n\n            if ($end && $csvTime > $end) {\n                continue;\n            }\n\n            $profile = [\n                'token' => $csvToken,\n                'ip' => $csvIp,\n                'method' => $csvMethod,\n                'url' => $csvUrl,\n                'time' => $csvTime,\n                'parent' => $csvParent,\n                'status_code' => $csvStatusCode,\n                'virtual_type' => $csvVirtualType ?: 'request',\n                'has_errors' => (bool) $csvHasErrors,\n            ];\n\n            if ($filter && !$filter($profile)) {\n                continue;\n            }\n\n            $result[$csvToken] = $profile;\n        }\n\n        fclose($file);\n\n        return array_values($result);\n    }\n\n    public function purge(): void\n    {\n        $flags = \\FilesystemIterator::SKIP_DOTS;\n        $iterator = new \\RecursiveDirectoryIterator($this->folder, $flags);\n        $iterator = new \\RecursiveIteratorIterator($iterator, \\RecursiveIteratorIterator::CHILD_FIRST);\n\n        foreach ($iterator as $file) {\n            if (is_file($file)) {\n                unlink($file);\n            } else {\n                rmdir($file);\n            }\n        }\n    }\n\n    public function read(string $token): ?Profile\n    {\n        return $this->doRead($token);\n    }\n\n    /**\n     * @throws \\RuntimeException\n     */\n    public function write(Profile $profile): bool\n    {\n        $file = $this->getFilename($profile->getToken());\n\n        $profileIndexed = is_file($file);\n        if (!$profileIndexed) {\n            // Create directory\n            $dir = \\dirname($file);\n            if (!is_dir($dir) && false === @mkdir($dir, 0o777, true) && !is_dir($dir)) {\n                throw new \\RuntimeException(\\sprintf('Unable to create the storage directory (%s).', $dir));\n            }\n        }\n\n        $profileToken = $profile->getToken();\n        // when there are errors in sub-requests, the parent and/or children tokens\n        // may equal the profile token, resulting in infinite loops\n        $parentToken = $profile->getParentToken() !== $profileToken ? $profile->getParentToken() : null;\n        $childrenToken = array_filter(array_map(static fn (Profile $p) => $profileToken !== $p->getToken() ? $p->getToken() : null, $profile->getChildren()));\n\n        // Store profile\n        $data = [\n            'token' => $profileToken,\n            'parent' => $parentToken,\n            'children' => $childrenToken,\n            'data' => $profile->getCollectors(),\n            'ip' => $profile->getIp(),\n            'method' => $profile->getMethod(),\n            'url' => $profile->getUrl(),\n            'time' => $profile->getTime(),\n            'status_code' => $profile->getStatusCode(),\n            'virtual_type' => $profile->getVirtualType() ?? 'request',\n            'has_errors' => $profile->hasErrors(),\n        ];\n\n        $data = serialize($data);\n\n        if (\\function_exists('gzencode')) {\n            $data = gzencode($data, 3);\n        }\n\n        if (false === file_put_contents($file, $data, \\LOCK_EX)) {\n            return false;\n        }\n\n        if (!$profileIndexed) {\n            // Add to index\n            if (false === $file = fopen($this->getIndexFilename(), 'a')) {\n                return false;\n            }\n\n            fputcsv($file, [\n                $profile->getToken(),\n                $profile->getIp(),\n                $profile->getMethod(),\n                $profile->getUrl(),\n                $profile->getTime() ?: time(),\n                $profile->getParentToken(),\n                $profile->getStatusCode(),\n                $profile->getVirtualType() ?? 'request',\n                $profile->hasErrors() ? '1' : '0',\n            ], ',', '\"', '\\\\');\n            fclose($file);\n\n            if (1 === random_int(1, 10)) {\n                $this->removeExpiredProfiles();\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Gets filename to store data, associated to the token.\n     */\n    protected function getFilename(string $token): string\n    {\n        // Uses 4 last characters, because first are mostly the same.\n        $folderA = substr($token, -2, 2);\n        $folderB = substr($token, -4, 2);\n\n        return $this->folder.'/'.$folderA.'/'.$folderB.'/'.$token;\n    }\n\n    /**\n     * Gets the index filename.\n     */\n    protected function getIndexFilename(): string\n    {\n        return $this->folder.'/index.csv';\n    }\n\n    /**\n     * Reads a line in the file, backward.\n     *\n     * This function automatically skips the empty lines and do not include the line return in result value.\n     *\n     * @param resource $file The file resource, with the pointer placed at the end of the line to read\n     */\n    protected function readLineFromFile($file): mixed\n    {\n        $line = '';\n        $position = ftell($file);\n\n        if (0 === $position) {\n            return null;\n        }\n\n        while (true) {\n            $chunkSize = min($position, 1024);\n            $position -= $chunkSize;\n            fseek($file, $position);\n\n            if (0 === $chunkSize) {\n                // bof reached\n                break;\n            }\n\n            $buffer = fread($file, $chunkSize);\n\n            if (false === ($upTo = strrpos($buffer, \"\\n\"))) {\n                $line = $buffer.$line;\n                continue;\n            }\n\n            $position += $upTo;\n            $line = substr($buffer, $upTo + 1).$line;\n            fseek($file, max(0, $position), \\SEEK_SET);\n\n            if ('' !== $line) {\n                break;\n            }\n        }\n\n        return '' === $line ? null : $line;\n    }\n\n    protected function createProfileFromData(string $token, array $data, ?Profile $parent = null): Profile\n    {\n        $profile = new Profile($token);\n        $profile->setIp($data['ip']);\n        $profile->setMethod($data['method']);\n        $profile->setUrl($data['url']);\n        $profile->setTime($data['time']);\n        $profile->setStatusCode($data['status_code']);\n        $profile->setVirtualType($data['virtual_type'] ?: 'request');\n        $profile->setHasErrors($data['has_errors'] ?? false);\n        $profile->setCollectors($data['data']);\n\n        if (!$parent && $data['parent']) {\n            $parent = $this->read($data['parent']);\n        }\n\n        if ($parent) {\n            $profile->setParent($parent);\n        }\n\n        foreach ($data['children'] as $token) {\n            if (null !== $childProfile = $this->doRead($token, $profile)) {\n                $profile->addChild($childProfile);\n            }\n        }\n\n        return $profile;\n    }\n\n    private function doRead($token, ?Profile $profile = null): ?Profile\n    {\n        if (!$token || !file_exists($file = $this->getFilename($token))) {\n            return null;\n        }\n\n        $h = fopen($file, 'r');\n        flock($h, \\LOCK_SH);\n        $data = stream_get_contents($h);\n        flock($h, \\LOCK_UN);\n        fclose($h);\n\n        if (\\function_exists('gzdecode')) {\n            $data = @gzdecode($data) ?: $data;\n        }\n\n        if (!$data = unserialize($data)) {\n            return null;\n        }\n\n        return $this->createProfileFromData($token, $data, $profile);\n    }\n\n    private function removeExpiredProfiles(): void\n    {\n        $minimalProfileTimestamp = time() - 2 * 86400;\n        $file = $this->getIndexFilename();\n        $handle = fopen($file, 'r');\n\n        if ($offset = is_file($file.'.offset') ? (int) file_get_contents($file.'.offset') : 0) {\n            fseek($handle, $offset);\n        }\n\n        while ($line = fgets($handle)) {\n            $values = str_getcsv($line, ',', '\"', '\\\\');\n\n            if (7 > \\count($values)) {\n                // skip invalid lines\n                $offset += \\strlen($line);\n                continue;\n            }\n\n            [$csvToken, , , , $csvTime] = $values;\n\n            if ($csvTime >= $minimalProfileTimestamp) {\n                break;\n            }\n\n            @unlink($this->getFilename($csvToken));\n            $offset += \\strlen($line);\n        }\n        fclose($handle);\n\n        file_put_contents($file.'.offset', $offset);\n    }\n}\n"
  },
  {
    "path": "Profiler/Profile.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Profiler;\n\nuse Symfony\\Component\\HttpKernel\\DataCollector\\DataCollectorInterface;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @final\n */\nclass Profile\n{\n    /**\n     * @var DataCollectorInterface[]\n     */\n    private array $collectors = [];\n\n    private ?string $ip = null;\n    private ?string $method = null;\n    private ?string $url = null;\n    private ?int $time = null;\n    private ?int $statusCode = null;\n    private ?self $parent = null;\n    private ?string $virtualType = null;\n    private bool $hasErrors = false;\n\n    /**\n     * @var Profile[]\n     */\n    private array $children = [];\n\n    public function __construct(\n        private string $token,\n    ) {\n    }\n\n    public function setToken(string $token): void\n    {\n        $this->token = $token;\n    }\n\n    /**\n     * Gets the token.\n     */\n    public function getToken(): string\n    {\n        return $this->token;\n    }\n\n    /**\n     * Sets the parent token.\n     */\n    public function setParent(self $parent): void\n    {\n        $this->parent = $parent;\n    }\n\n    /**\n     * Returns the parent profile.\n     */\n    public function getParent(): ?self\n    {\n        return $this->parent;\n    }\n\n    /**\n     * Returns the parent token.\n     */\n    public function getParentToken(): ?string\n    {\n        return $this->parent?->getToken();\n    }\n\n    /**\n     * Returns the IP.\n     */\n    public function getIp(): ?string\n    {\n        return $this->ip;\n    }\n\n    public function setIp(?string $ip): void\n    {\n        $this->ip = $ip;\n    }\n\n    /**\n     * Returns the request method.\n     */\n    public function getMethod(): ?string\n    {\n        return $this->method;\n    }\n\n    public function setMethod(string $method): void\n    {\n        $this->method = $method;\n    }\n\n    /**\n     * Returns the URL.\n     */\n    public function getUrl(): ?string\n    {\n        return $this->url;\n    }\n\n    public function setUrl(?string $url): void\n    {\n        $this->url = $url;\n    }\n\n    public function getTime(): int\n    {\n        return $this->time ?? 0;\n    }\n\n    public function setTime(int $time): void\n    {\n        $this->time = $time;\n    }\n\n    public function setStatusCode(int $statusCode): void\n    {\n        $this->statusCode = $statusCode;\n    }\n\n    public function getStatusCode(): ?int\n    {\n        return $this->statusCode;\n    }\n\n    /**\n     * @internal\n     */\n    public function setVirtualType(?string $virtualType): void\n    {\n        $this->virtualType = $virtualType;\n    }\n\n    /**\n     * @internal\n     */\n    public function getVirtualType(): ?string\n    {\n        return $this->virtualType;\n    }\n\n    public function hasErrors(): bool\n    {\n        return $this->hasErrors;\n    }\n\n    public function setHasErrors(bool $hasErrors): void\n    {\n        $this->hasErrors = $hasErrors;\n    }\n\n    /**\n     * Finds children profilers.\n     *\n     * @return self[]\n     */\n    public function getChildren(): array\n    {\n        return $this->children;\n    }\n\n    /**\n     * Sets children profiler.\n     *\n     * @param Profile[] $children\n     */\n    public function setChildren(array $children): void\n    {\n        $this->children = [];\n        foreach ($children as $child) {\n            $this->addChild($child);\n        }\n    }\n\n    /**\n     * Adds the child token.\n     */\n    public function addChild(self $child): void\n    {\n        $this->children[] = $child;\n        $child->setParent($this);\n    }\n\n    public function getChildByToken(string $token): ?self\n    {\n        foreach ($this->children as $child) {\n            if ($token === $child->getToken()) {\n                return $child;\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Gets a Collector by name.\n     *\n     * @throws \\InvalidArgumentException if the collector does not exist\n     */\n    public function getCollector(string $name): DataCollectorInterface\n    {\n        if (!isset($this->collectors[$name])) {\n            throw new \\InvalidArgumentException(\\sprintf('Collector \"%s\" does not exist.', $name));\n        }\n\n        return $this->collectors[$name];\n    }\n\n    /**\n     * Gets the Collectors associated with this profile.\n     *\n     * @return DataCollectorInterface[]\n     */\n    public function getCollectors(): array\n    {\n        return $this->collectors;\n    }\n\n    /**\n     * Sets the Collectors associated with this profile.\n     *\n     * @param DataCollectorInterface[] $collectors\n     */\n    public function setCollectors(array $collectors): void\n    {\n        $this->collectors = [];\n        foreach ($collectors as $collector) {\n            $this->addCollector($collector);\n        }\n    }\n\n    /**\n     * Adds a Collector.\n     */\n    public function addCollector(DataCollectorInterface $collector): void\n    {\n        $this->collectors[$collector->getName()] = $collector;\n    }\n\n    public function hasCollector(string $name): bool\n    {\n        return isset($this->collectors[$name]);\n    }\n\n    public function __serialize(): array\n    {\n        return [\n            'token' => $this->token,\n            'parent' => $this->parent,\n            'children' => $this->children,\n            'collectors' => $this->collectors,\n            'ip' => $this->ip,\n            'method' => $this->method,\n            'url' => $this->url,\n            'time' => $this->time,\n            'statusCode' => $this->statusCode,\n            'virtualType' => $this->virtualType,\n            'hasErrors' => $this->hasErrors,\n        ];\n    }\n}\n"
  },
  {
    "path": "Profiler/Profiler.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Profiler;\n\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\HttpFoundation\\Exception\\ConflictingHeadersException;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\DataCollectorInterface;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\LateDataCollectorInterface;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\LoggerDataCollector;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * Profiler.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass Profiler implements ResetInterface\n{\n    /**\n     * @var DataCollectorInterface[]\n     */\n    private array $collectors = [];\n\n    private bool $initiallyEnabled = true;\n\n    public function __construct(\n        private ProfilerStorageInterface $storage,\n        private ?LoggerInterface $logger = null,\n        private bool $enabled = true,\n    ) {\n        $this->initiallyEnabled = $enabled;\n    }\n\n    /**\n     * Disables the profiler.\n     */\n    public function disable(): void\n    {\n        $this->enabled = false;\n    }\n\n    /**\n     * Enables the profiler.\n     */\n    public function enable(): void\n    {\n        $this->enabled = true;\n    }\n\n    public function isEnabled(): bool\n    {\n        return $this->enabled;\n    }\n\n    /**\n     * Loads the Profile for the given Response.\n     */\n    public function loadProfileFromResponse(Response $response): ?Profile\n    {\n        if (!$token = $response->headers->get('X-Debug-Token')) {\n            return null;\n        }\n\n        return $this->loadProfile($token);\n    }\n\n    /**\n     * Loads the Profile for the given token.\n     */\n    public function loadProfile(string $token): ?Profile\n    {\n        return $this->storage->read($token);\n    }\n\n    /**\n     * Saves a Profile.\n     */\n    public function saveProfile(Profile $profile): bool\n    {\n        // late collect\n        foreach ($profile->getCollectors() as $collector) {\n            if ($collector instanceof LateDataCollectorInterface) {\n                $collector->lateCollect();\n            }\n        }\n\n        // Update hasErrors flag to include error-level logs (available after lateCollect)\n        if (!$profile->hasErrors()\n            && $profile->hasCollector('logger')\n            && ($logger = $profile->getCollector('logger')) instanceof LoggerDataCollector\n            && $logger->countErrors() > 0\n        ) {\n            $profile->setHasErrors(true);\n        }\n\n        if (!($ret = $this->storage->write($profile)) && null !== $this->logger) {\n            $this->logger->warning('Unable to store the profiler information.', ['configured_storage' => $this->storage::class]);\n        }\n\n        return $ret;\n    }\n\n    /**\n     * Purges all data from the storage.\n     */\n    public function purge(): void\n    {\n        $this->storage->purge();\n    }\n\n    /**\n     * Finds profiler tokens for the given criteria.\n     *\n     * @param int|null      $limit  The maximum number of tokens to return\n     * @param string|null   $start  The start date to search from\n     * @param string|null   $end    The end date to search to\n     * @param \\Closure|null $filter A filter to apply on the list of tokens\n     *\n     * @see https://php.net/datetime.formats for the supported date/time formats\n     */\n    public function find(?string $ip, ?string $url, ?int $limit, ?string $method, ?string $start, ?string $end, ?string $statusCode = null, ?\\Closure $filter = null): array\n    {\n        return $this->storage->find($ip, $url, $limit, $method, $this->getTimestamp($start), $this->getTimestamp($end), $statusCode, $filter);\n    }\n\n    /**\n     * Collects data for the given Response.\n     */\n    public function collect(Request $request, Response $response, ?\\Throwable $exception = null): ?Profile\n    {\n        if (false === $this->enabled) {\n            return null;\n        }\n\n        $profile = new Profile(bin2hex(random_bytes(3)));\n        $profile->setTime(time());\n        $profile->setUrl($request->getUri());\n        $profile->setMethod($request->getMethod());\n        $profile->setStatusCode($response->getStatusCode());\n        try {\n            $profile->setIp($request->getClientIp());\n        } catch (ConflictingHeadersException) {\n            $profile->setIp('Unknown');\n        }\n\n        if ($request->attributes->has('_virtual_type')) {\n            $profile->setVirtualType($request->attributes->get('_virtual_type'));\n        }\n\n        $profile->setHasErrors(null !== $exception);\n\n        if ($prevToken = $response->headers->get('X-Debug-Token')) {\n            $response->headers->set('X-Previous-Debug-Token', $prevToken);\n        }\n\n        $response->headers->set('X-Debug-Token', $profile->getToken());\n\n        foreach ($this->collectors as $collector) {\n            $collector->collect($request, $response, $exception);\n\n            // we need to clone for sub-requests\n            $profile->addCollector(clone $collector);\n        }\n\n        return $profile;\n    }\n\n    public function reset(): void\n    {\n        foreach ($this->collectors as $collector) {\n            $collector->reset();\n        }\n        $this->enabled = $this->initiallyEnabled;\n    }\n\n    /**\n     * Gets the Collectors associated with this profiler.\n     */\n    public function all(): array\n    {\n        return $this->collectors;\n    }\n\n    /**\n     * Sets the Collectors associated with this profiler.\n     *\n     * @param DataCollectorInterface[] $collectors An array of collectors\n     */\n    public function set(array $collectors = []): void\n    {\n        $this->collectors = [];\n        foreach ($collectors as $collector) {\n            $this->add($collector);\n        }\n    }\n\n    /**\n     * Adds a Collector.\n     */\n    public function add(DataCollectorInterface $collector): void\n    {\n        $this->collectors[$collector->getName()] = $collector;\n    }\n\n    /**\n     * Returns true if a Collector for the given name exists.\n     *\n     * @param string $name A collector name\n     */\n    public function has(string $name): bool\n    {\n        return isset($this->collectors[$name]);\n    }\n\n    /**\n     * Gets a Collector by name.\n     *\n     * @param string $name A collector name\n     *\n     * @throws \\InvalidArgumentException if the collector does not exist\n     */\n    public function get(string $name): DataCollectorInterface\n    {\n        if (!isset($this->collectors[$name])) {\n            throw new \\InvalidArgumentException(\\sprintf('Collector \"%s\" does not exist.', $name));\n        }\n\n        return $this->collectors[$name];\n    }\n\n    private function getTimestamp(?string $value): ?int\n    {\n        if (null === $value || '' === $value) {\n            return null;\n        }\n\n        try {\n            $value = new \\DateTimeImmutable(is_numeric($value) ? '@'.$value : $value);\n        } catch (\\Exception) {\n            return null;\n        }\n\n        return $value->getTimestamp();\n    }\n}\n"
  },
  {
    "path": "Profiler/ProfilerStateChecker.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Profiler;\n\nuse Psr\\Container\\ContainerInterface;\n\nclass ProfilerStateChecker\n{\n    public function __construct(\n        private ContainerInterface $container,\n        private bool $defaultEnabled,\n    ) {\n    }\n\n    public function isProfilerEnabled(): bool\n    {\n        return $this->container->get('profiler')?->isEnabled() ?? $this->defaultEnabled;\n    }\n\n    public function isProfilerDisabled(): bool\n    {\n        return !$this->isProfilerEnabled();\n    }\n}\n"
  },
  {
    "path": "Profiler/ProfilerStorageInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Profiler;\n\n/**\n * ProfilerStorageInterface.\n *\n * This interface exists for historical reasons. The only supported\n * implementation is FileProfilerStorage.\n *\n * As the profiler must only be used on non-production servers, the file storage\n * is more than enough and no other implementations will ever be supported.\n *\n * @internal\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface ProfilerStorageInterface\n{\n    /**\n     * Finds profiler tokens for the given criteria.\n     *\n     * @param int|null      $limit      The maximum number of tokens to return\n     * @param int|null      $start      The start date to search from\n     * @param int|null      $end        The end date to search to\n     * @param string|null   $statusCode The response status code\n     * @param \\Closure|null $filter     A filter to apply on the list of tokens\n     */\n    public function find(?string $ip, ?string $url, ?int $limit, ?string $method, ?int $start = null, ?int $end = null, ?string $statusCode = null, ?\\Closure $filter = null): array;\n\n    /**\n     * Reads data associated with the given token.\n     *\n     * The method returns false if the token does not exist in the storage.\n     */\n    public function read(string $token): ?Profile;\n\n    /**\n     * Saves a Profile.\n     */\n    public function write(Profile $profile): bool;\n\n    /**\n     * Purges all data from the database.\n     */\n    public function purge(): void;\n}\n"
  },
  {
    "path": "README.md",
    "content": "HttpKernel Component\n====================\n\nThe HttpKernel component provides a structured process for converting a Request\ninto a Response by making use of the EventDispatcher component. It's flexible\nenough to create full-stack frameworks, micro-frameworks or advanced CMS systems like Drupal.\n\nResources\n---------\n\n * [Documentation](https://symfony.com/doc/current/components/http_kernel.html)\n * [Contributing](https://symfony.com/doc/current/contributing/index.html)\n * [Report issues](https://github.com/symfony/symfony/issues) and\n   [send Pull Requests](https://github.com/symfony/symfony/pulls)\n   in the [main Symfony repository](https://github.com/symfony/symfony)\n"
  },
  {
    "path": "RebootableInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel;\n\n/**\n * Allows the Kernel to be rebooted using a temporary cache directory.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\ninterface RebootableInterface\n{\n    /**\n     * Reboots a kernel.\n     *\n     * The getBuildDir() method of a rebootable kernel should not be called\n     * while building the container. Use the %kernel.build_dir% parameter instead.\n     *\n     * @param string|null $warmupDir pass null to reboot in the regular build directory\n     */\n    public function reboot(?string $warmupDir): void;\n}\n"
  },
  {
    "path": "Resources/welcome.html.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n$renderSymfonyLogoSvg = <<<SVG\n<svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" height=\"48\" width=\"48\" viewBox=\"0 0 64.9 64.9\"><path fill=\"currentColor\" d=\"M32.5 0A32.5 32.5 0 0 0 0 32.5a32.5 32.5 0 0 0 32.5 32.4 32.5 32.5 0 0 0 32.4-32.4A32.5 32.5 0 0 0 32.5 0Zm14.1 12c3.3-.1 5.8 1.4 6 3.8 0 1-.6 3-2.6 3-1.5 0-2.6-.9-2.6-2.2 0-.5 0-1 .4-1.5.4-.6.4-.7.4-1 0-.9-1.3-.9-1.7-.9-4.8.2-6.1 6.8-7.2 12.1l-.5 2.8c2.8.4 4.8 0 6-.8 1.5-1-.5-2-.2-3.2a2.3 2.3 0 0 1 2.1-1.8c1.2 0 2 1.2 2 2.5 0 2-2.7 5-8.2 4.8l-2-.1-1 5.7c-.9 4.3-2.1 10.3-6.5 15.4a13.4 13.4 0 0 1-9.4 5.3c-3.2.1-5.4-1.6-5.4-3.9-.1-2.2 1.9-3.4 3.1-3.5 1.8 0 3 1.2 3 2.6 0 1.3-.6 1.6-1 1.9-.3.2-.7.4-.7 1 0 .1.2.6 1 .6 1.3 0 2.2-.7 2.9-1.2 3.1-2.6 4.3-7.1 5.9-15.4l.3-2c.6-2.8 1.2-5.8 2-8.8-2.1-1.6-3.5-3.7-6.4-4.5-2-.6-3.3-.1-4.2 1a3 3 0 0 0 .3 4l1.7 1.9c2 2.3 3.1 4.1 2.7 6.6-.7 3.9-5.3 6.9-10.9 5.2-4.7-1.4-5.6-4.8-5-6.6.5-1.6 1.8-2 3-1.6 1.4.5 2 2 1.5 3.3 0 .2 0 .4-.2.7l-.6 1c-.3 1 1 1.7 2 2 2.1.7 4.2-.4 4.7-2.1.5-1.6-.5-2.7-1-3.1l-2-2.1c-.8-1-2.8-3.9-1.9-7a6.8 6.8 0 0 1 2.4-3.5c2.4-1.8 5-2 7.6-1.3 3.2.9 4.8 3 6.8 4.7a28 28 0 0 1 5.1-9.3c2.2-2.6 5-4.4 8.3-4.5z\"/></svg>\nSVG;\n\n// SVG icons from the Tabler Icons project\n// MIT License - Copyright (c) 2020-2023 Paweł Kuna\n// https://github.com/tabler/tabler-icons/blob/master/LICENSE\n\n$renderBoxIconSvg = <<<SVG\n<svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" class=\"icon icon-tabler icon-tabler-box\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n    <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\"/>\n    <path d=\"M12 3l8 4.5l0 9l-8 4.5l-8 -4.5l0 -9l8 -4.5\" />\n    <path d=\"M12 12l8 -4.5\" />\n    <path d=\"M12 12l0 9\" />\n    <path d=\"M12 12l-8 -4.5\" />\n</svg>\nSVG;\n\n$renderFolderIconSvg = <<<SVG\n<svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" class=\"icon icon-tabler icon-tabler-folder-open\" width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n    <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\"></path>\n    <path d=\"M5 19l2.757 -7.351a1 1 0 0 1 .936 -.649h12.307a1 1 0 0 1 .986 1.164l-.996 5.211a2 2 0 0 1 -1.964 1.625h-14.026a2 2 0 0 1 -2 -2v-11a2 2 0 0 1 2 -2h4l3 3h7a2 2 0 0 1 2 2v2\"></path>\n</svg>\nSVG;\n\n$renderInfoIconSvg = <<<SVG\n<svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" class=\"icon icon-tabler icon-tabler-info-circle\" width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n    <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\"></path>\n    <path d=\"M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0\"></path>\n    <path d=\"M12 9h.01\"></path>\n    <path d=\"M11 12h1v4h1\"></path>\n</svg>\nSVG;\n\n$renderNextStepIconSvg = <<<SVG\n<svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" class=\"icon icon-tabler icon-tabler-square-chevrons-right\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n    <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\"/>\n    <path d=\"M8 9l3 3l-3 3\" />\n    <path d=\"M13 9l3 3l-3 3\" />\n    <path d=\"M3 5a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-14z\" />\n</svg>\nSVG;\n\n$renderLearnIconSvg = <<<SVG\n<svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" class=\"icon icon-tabler icon-tabler-book\" width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n    <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\"></path>\n    <path d=\"M3 19a9 9 0 0 1 9 0a9 9 0 0 1 9 0\"></path>\n    <path d=\"M3 6a9 9 0 0 1 9 0a9 9 0 0 1 9 0\"></path>\n    <path d=\"M3 6l0 13\"></path>\n    <path d=\"M12 6l0 13\"></path>\n    <path d=\"M21 6l0 13\"></path>\n</svg>\nSVG;\n\n$renderCommunityIconSvg = <<<SVG\n<svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" class=\"icon icon-tabler icon-tabler-users\" width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n    <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\"></path>\n    <path d=\"M9 7m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0\"></path>\n    <path d=\"M3 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2\"></path>\n    <path d=\"M16 3.13a4 4 0 0 1 0 7.75\"></path>\n    <path d=\"M21 21v-2a4 4 0 0 0 -3 -3.85\"></path>\n</svg>\nSVG;\n\n$renderUpdatesIconSvg = <<<SVG\n<svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" class=\"icon icon-tabler icon-tabler-bell-ringing\" width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n    <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\"/>\n    <path d=\"M10 5a2 2 0 0 1 4 0a7 7 0 0 1 4 6v3a4 4 0 0 0 2 3h-16a4 4 0 0 0 2 -3v-3a7 7 0 0 1 4 -6\" />\n    <path d=\"M9 17v1a3 3 0 0 0 6 0v-1\" />\n    <path d=\"M21 6.727a11.05 11.05 0 0 0 -2.794 -3.727\" />\n    <path d=\"M3 6.727a11.05 11.05 0 0 1 2.792 -3.727\" />\n</svg>\nSVG;\n\n$renderWavesSvg = <<<SVG\n<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" aria-hidden=\"true\" focusable=\"false\" style=\"pointer-events: none\" class=\"wave\" width=\"100%\" height=\"50px\" preserveAspectRatio=\"none\" viewBox=\"0 0 1920 75\">\n    <defs>\n        <style>\n            .a { fill: none; }\n            .b { clip-path: url(#a); }\n            .c, .d { fill: var(--light-color); }\n            .d { opacity: 0.5; isolation: isolate; }\n            @keyframes waveMotion {\n                0% { transform: scaleX(1) translateX(0); }\n                50% { transform: scaleX(1.5) translateX(-30%); }\n                0% { transform: scaleX(1) translateX(0); }\n            }\n\n            .b:nth-child(5) { animation: waveMotion 14s infinite alternate; }\n            .b:nth-child(2) { animation: waveMotion 12s infinite alternate; }\n            .b:nth-child(3) { animation: waveMotion 13s infinite alternate; }\n            .b:nth-child(4) { animation: waveMotion 8s infinite alternate; }\n\n            @media (prefers-reduced-motion) {\n                .b { animation: none !important; }\n            }\n        </style>\n        <clipPath id=\"a\"><rect class=\"a\" width=\"1920\" height=\"75\"></rect></clipPath>\n    </defs>\n    <g class=\"b\">\n        <path class=\"c\" d=\"M1963,327H-105V65A2647.49,2647.49,0,0,1,431,19c217.7,3.5,239.6,30.8,470,36,297.3,6.7,367.5-36.2,642-28a2511.41,2511.41,0,0,1,420,48\"></path>\n    </g>\n    <g class=\"b\">\n        <path class=\"d\" d=\"M-127,404H1963V44c-140.1-28-343.3-46.7-566,22-75.5,23.3-118.5,45.9-162,64-48.6,20.2-404.7,128-784,0C355.2,97.7,341.6,78.3,235,50,86.6,10.6-41.8,6.9-127,10\"></path>\n    </g>\n    <g class=\"b\">\n        <path class=\"d\" d=\"M1979,462-155,446V106C251.8,20.2,576.6,15.9,805,30c167.4,10.3,322.3,32.9,680,56,207,13.4,378,20.3,494,24\"></path>\n    </g>\n    <g class=\"b\">\n        <path class=\"d\" d=\"M1998,484H-243V100c445.8,26.8,794.2-4.1,1035-39,141-20.4,231.1-40.1,378-45,349.6-11.6,636.7,73.8,828,150\"></path>\n    </g>\n</svg>\nSVG;\n?>\n<!DOCTYPE html>\n<html dir=\"ltr\" lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"robots\" content=\"noindex, nofollow, noarchive, nosnippet, noodp, notranslate, noimageindex\" />\n    <title>Welcome to Symfony!</title>\n    <link rel=\"icon\" href=\"data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>👋</text></svg>\" />\n    <style>\n        :root {\n            --hue: <?php echo random_int(0, 360); ?>;\n            --light-color: hsl(var(--hue), 20%, 95%);\n            --dark-color: hsl(var(--hue), 20%, 40%);\n        }\n\n        body {\n            -webkit-text-size-adjust: 100%;\n            background: var(--light-color);\n            color: var(--dark-color);\n            font-feature-settings: normal;\n            font-family: ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;\n            margin: 0;\n            padding: 0;\n        }\n\n        @keyframes stars{\n            0% { transform: translateX(0) translateY(0px); }\n            33% { transform: translateX(-20px)  translateY(-20px); }\n            66% { transform: translateX(-40px) translateY(-40px); }\n            100% { transform: translateX(0px)  translateY(0px); }\n        }\n        header a, main a { color: inherit; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; }\n        header a:hover, main a:hover { text-decoration-thickness: 3px; text-decoration-skip-ink: none; }\n        header a:active, main a:active { position: relative; top: 1px; }\n        header { background: radial-gradient(ellipse at bottom, var(--dark-color) 0%, hsl(var(--hue), 20%, 13%) 100%); background-attachment: fixed; color: var(--light-color); overflow: hidden; position: relative }\n        header:before { content: ''; position: absolute; background: transparent; width: 100%; height: 100%; backdrop-filter: blur(1px); z-index: 1; }\n        @media (prefers-reduced-motion) {\n            header:after { animation: none !important; }\n        }\n        header:after { animation: stars 30s infinite; content: \"\"; position: absolute; height: 2px; width: 2px; top: -2px; left: 0; background: white; box-shadow: 778px 1019px 0 0 rgba(255, 255, 255, 0.826) , 1075px 1688px 0 0 rgba(255,255,255, 0.275) , 388px 1021px 0 0 rgba(255,255,255, 0.259) , 1238px 626px 0 0 rgba(255,255,255, 0.469) , 997px 904px 0 0 rgba(255,255,255, 0.925) , 921px 1345px 0 0 rgba(255,255,255, 0.698) , 337px 1236px 0 0 rgba(255,255,255, 0.838) , 460px 569px 0 0 rgba(255,255,255, 0.01) , 690px 1488px 0 0 rgba(255,255,255, 0.154) , 859px 926px 0 0 rgba(255,255,255, 0.515) , 1272px 791px 0 0 rgba(255,255,255, 1) , 238px 1256px 0 0 rgba(255,255,255, 0.633) , 1486px 897px 0 0 rgba(255,255,255, 0.88) , 667px 6px 0 0 rgba(255,255,255, 0.508) , 853px 504px 0 0 rgba(255,255,255, 0.248) , 1329px 1778px 0 0 rgba(255,255,255, 0.217) , 768px 1340px 0 0 rgba(255,255,255, 0.792) , 631px 1383px 0 0 rgba(255,255,255, 0.698) , 991px 1603px 0 0 rgba(255,255,255, 0.939) , 1778px 1767px 0 0 rgba(255,255,255, 0.784) , 285px 546px 0 0 rgba(255,255,255, 0.8) , 1224px 1333px 0 0 rgba(255,255,255, 0.676) , 1154px 397px 0 0 rgba(255,255,255, 0.974) , 1210px 1004px 0 0 rgba(255,255,255, 0.894) , 1632px 953px 0 0 rgba(255,255,255, 0.281) , 449px 1144px 0 0 rgba(255,255,255, 0.706) , 1426px 771px 0 0 rgba(255,255,255, 0.737) , 1438px 1634px 0 0 rgba(255,255,255, 0.984) , 806px 168px 0 0 rgba(255,255,255, 0.807) , 731px 1067px 0 0 rgba(255,255,255, 0.734) , 1731px 1785px 0 0 rgba(255,255,255, 0.528) , 23px 975px 0 0 rgba(255,255,255, 0.068) , 575px 1088px 0 0 rgba(255,255,255, 0.876) , 1205px 1668px 0 0 rgba(255,255,255, 0.601) , 18px 1457px 0 0 rgba(255,255,255, 0.176) , 252px 1163px 0 0 rgba(255,255,255, 0.416) , 1752px 1px 0 0 rgba(255,255,255, 0.374) , 382px 767px 0 0 rgba(255,255,255, 0.073) , 133px 1462px 0 0 rgba(255,255,255, 0.706) , 851px 1166px 0 0 rgba(255,255,255, 0.535) , 374px 921px 0 0 rgba(255,255,255, 0.548) , 554px 1598px 0 0 rgba(255,255,255, 0.062) , 314px 685px 0 0 rgba(255,255,255, 0.187) , 1443px 209px 0 0 rgba(255,255,255, 0.097) , 1774px 1625px 0 0 rgba(255,255,255, 0.32) , 58px 278px 0 0 rgba(255,255,255, 0.684) , 986px 338px 0 0 rgba(255,255,255, 0.272) , 718px 1357px 0 0 rgba(255,255,255, 0.317) , 722px 983px 0 0 rgba(255,255,255, 0.568) , 1124px 992px 0 0 rgba(255,255,255, 0.199) , 581px 619px 0 0 rgba(255,255,255, 0.44) , 1120px 285px 0 0 rgba(255,255,255, 0.425) , 702px 138px 0 0 rgba(255,255,255, 0.816) , 262px 767px 0 0 rgba(255,255,255, 0.92) , 1204px 38px 0 0 rgba(255,255,255, 0.197) , 1196px 410px 0 0 rgba(255,255,255, 0.453) , 707px 699px 0 0 rgba(255,255,255, 0.481) , 1590px 1488px 0 0 rgba(255,255,255, 0.559) , 879px 1763px 0 0 rgba(255,255,255, 0.241) , 106px 686px 0 0 rgba(255,255,255, 0.175) , 158px 569px 0 0 rgba(255,255,255, 0.549) , 711px 1219px 0 0 rgba(255,255,255, 0.476) , 1339px 53px 0 0 rgba(255,255,255, 0.275) , 1410px 172px 0 0 rgba(255,255,255, 0.449) , 1601px 1484px 0 0 rgba(255,255,255, 0.988) , 1328px 1752px 0 0 rgba(255,255,255, 0.827) , 1733px 1475px 0 0 rgba(255,255,255, 0.567) , 559px 742px 0 0 rgba(255,255,255, 0.423) , 772px 844px 0 0 rgba(255,255,255, 0.039) , 602px 520px 0 0 rgba(255,255,255, 0.284) , 1158px 1067px 0 0 rgba(255,255,255, 0.066) , 1562px 730px 0 0 rgba(255,255,255, 0.086) , 1792px 615px 0 0 rgba(255,255,255, 0.438) , 1085px 1191px 0 0 rgba(255,255,255, 0.157) , 1402px 1087px 0 0 rgba(255,255,255, 0.797) , 569px 1685px 0 0 rgba(255,255,255, 0.992) , 1608px 52px 0 0 rgba(255,255,255, 0.302) , 1697px 1246px 0 0 rgba(255,255,255, 0.295) , 899px 1490px 0 0 rgba(255,255,255, 0.73) , 993px 901px 0 0 rgba(255,255,255, 0.961) , 1193px 1023px 0 0 rgba(255,255,255, 0.671) , 1224px 176px 0 0 rgba(255,255,255, 0.786) , 721px 1308px 0 0 rgba(255,255,255, 0.691) , 1702px 730px 0 0 rgba(255,255,255, 0.841) , 1480px 1498px 0 0 rgba(255,255,255, 0.655) , 181px 1612px 0 0 rgba(255,255,255, 0.588) , 1776px 679px 0 0 rgba(255,255,255, 0.821) , 892px 706px 0 0 rgba(255,255,255, 0.056) , 859px 267px 0 0 rgba(255,255,255, 0.565) , 784px 1285px 0 0 rgba(255,255,255, 0.029) , 1561px 1198px 0 0 rgba(255,255,255, 0.315) , 205px 421px 0 0 rgba(255,255,255, 0.584) , 236px 406px 0 0 rgba(255,255,255, 0.166) , 1259px 689px 0 0 rgba(255,255,255, 0.321) , 448px 317px 0 0 rgba(255,255,255, 0.495) , 1318px 466px 0 0 rgba(255,255,255, 0.275) , 1053px 297px 0 0 rgba(255,255,255, 0.035) , 716px 538px 0 0 rgba(255,255,255, 0.764) , 381px 207px 0 0 rgba(255,255,255, 0.692) , 871px 1140px 0 0 rgba(255,255,255, 0.342) , 361px 53px 0 0 rgba(255,255,255, 0.984) , 1565px 1593px 0 0 rgba(255,255,255, 0.102) , 145px 277px 0 0 rgba(255,255,255, 0.866) , 220px 1503px 0 0 rgba(255,255,255, 0.936) , 1068px 1475px 0 0 rgba(255,255,255, 0.156) , 1548px 483px 0 0 rgba(255,255,255, 0.768) , 710px 103px 0 0 rgba(255,255,255, 0.809) , 1660px 921px 0 0 rgba(255,255,255, 0.952) , 462px 1252px 0 0 rgba(255,255,255, 0.825) , 1123px 1628px 0 0 rgba(255,255,255, 0.409) , 1274px 729px 0 0 rgba(255,255,255, 0.26) , 1739px 679px 0 0 rgba(255,255,255, 0.83) , 1550px 1518px 0 0 rgba(255,255,255, 0.25) , 1624px 346px 0 0 rgba(255,255,255, 0.557) , 1023px 579px 0 0 rgba(255,255,255, 0.854) , 217px 661px 0 0 rgba(255,255,255, 0.731) , 1504px 549px 0 0 rgba(255,255,255, 0.705) , 939px 5px 0 0 rgba(255,255,255, 0.389) , 284px 735px 0 0 rgba(255,255,255, 0.355) , 13px 1679px 0 0 rgba(255,255,255, 0.712) , 137px 1592px 0 0 rgba(255,255,255, 0.619) , 1113px 505px 0 0 rgba(255,255,255, 0.651) , 1584px 510px 0 0 rgba(255,255,255, 0.41) , 346px 913px 0 0 rgba(255,255,255, 0.09) , 198px 1490px 0 0 rgba(255,255,255, 0.103) , 447px 1128px 0 0 rgba(255,255,255, 0.314) , 1356px 324px 0 0 rgba(255,255,255, 0.324) , 648px 667px 0 0 rgba(255,255,255, 0.155) , 442px 260px 0 0 rgba(255,255,255, 0.22) , 210px 401px 0 0 rgba(255,255,255, 0.682) , 422px 1772px 0 0 rgba(255,255,255, 0.671) , 276px 349px 0 0 rgba(255,255,255, 0.683) , 131px 539px 0 0 rgba(255,255,255, 0.977) , 892px 94px 0 0 rgba(255,255,255, 0.081) , 1295px 222px 0 0 rgba(255,255,255, 0.961) , 5px 1727px 0 0 rgba(255,255,255, 0.311) , 714px 1148px 0 0 rgba(255,255,255, 0.846) , 1455px 1182px 0 0 rgba(255,255,255, 0.313) , 1370px 708px 0 0 rgba(255,255,255, 0.824) , 812px 433px 0 0 rgba(255,255,255, 0.75) , 1110px 558px 0 0 rgba(255,255,255, 0.709) , 1132px 1543px 0 0 rgba(255,255,255, 0.868) , 644px 610px 0 0 rgba(255,255,255, 0.166) , 269px 1481px 0 0 rgba(255,255,255, 0.889) , 1712px 590px 0 0 rgba(255,255,255, 0.139) , 1159px 599px 0 0 rgba(255,255,255, 0.992) , 1551px 209px 0 0 rgba(255,255,255, 0.033) , 1020px 1721px 0 0 rgba(255,255,255, 0.028) , 216px 373px 0 0 rgba(255,255,255, 0.665) , 877px 532px 0 0 rgba(255,255,255, 0.686) , 1326px 885px 0 0 rgba(255,255,255, 0.517) , 972px 1704px 0 0 rgba(255,255,255, 0.499) , 749px 181px 0 0 rgba(255,255,255, 0.712) , 1511px 1650px 0 0 rgba(255,255,255, 0.101) , 1432px 183px 0 0 rgba(255,255,255, 0.545) , 1541px 1338px 0 0 rgba(255,255,255, 0.71) , 513px 1406px 0 0 rgba(255,255,255, 0.17) , 1314px 1197px 0 0 rgba(255,255,255, 0.789) , 824px 1659px 0 0 rgba(255,255,255, 0.597) , 308px 298px 0 0 rgba(255,255,255, 0.917) , 1225px 659px 0 0 rgba(255,255,255, 0.229) , 1253px 257px 0 0 rgba(255,255,255, 0.631) , 1653px 185px 0 0 rgba(255,255,255, 0.113) , 336px 614px 0 0 rgba(255,255,255, 0.045) , 1093px 898px 0 0 rgba(255,255,255, 0.617) , 730px 5px 0 0 rgba(255,255,255, 0.11) , 785px 645px 0 0 rgba(255,255,255, 0.516) , 989px 678px 0 0 rgba(255,255,255, 0.917) , 1511px 1614px 0 0 rgba(255,255,255, 0.938) , 584px 1117px 0 0 rgba(255,255,255, 0.631) , 534px 1012px 0 0 rgba(255,255,255, 0.668) , 1325px 1778px 0 0 rgba(255,255,255, 0.293) , 1632px 754px 0 0 rgba(255,255,255, 0.26) , 78px 1258px 0 0 rgba(255,255,255, 0.52) , 779px 1691px 0 0 rgba(255,255,255, 0.878) , 253px 1706px 0 0 rgba(255,255,255, 0.75) , 1358px 245px 0 0 rgba(255,255,255, 0.027) , 361px 1629px 0 0 rgba(255,255,255, 0.238) , 1134px 232px 0 0 rgba(255,255,255, 0.387) , 1685px 777px 0 0 rgba(255,255,255, 0.156) , 515px 724px 0 0 rgba(255,255,255, 0.863) , 588px 1728px 0 0 rgba(255,255,255, 0.159) , 1132px 47px 0 0 rgba(255,255,255, 0.691) , 315px 1446px 0 0 rgba(255,255,255, 0.782) , 79px 233px 0 0 rgba(255,255,255, 0.317) , 1498px 1050px 0 0 rgba(255,255,255, 0.358) , 30px 1073px 0 0 rgba(255,255,255, 0.939) , 1637px 620px 0 0 rgba(255,255,255, 0.141) , 1736px 1683px 0 0 rgba(255,255,255, 0.682) , 1298px 1505px 0 0 rgba(255,255,255, 0.863) , 972px 85px 0 0 rgba(255,255,255, 0.941) , 349px 1356px 0 0 rgba(255,255,255, 0.672) , 1545px 1429px 0 0 rgba(255,255,255, 0.859) , 1076px 467px 0 0 rgba(255,255,255, 0.024) , 189px 1647px 0 0 rgba(255,255,255, 0.838) , 423px 1722px 0 0 rgba(255,255,255, 0.771) , 1691px 1719px 0 0 rgba(255,255,255, 0.676) , 1747px 658px 0 0 rgba(255,255,255, 0.255) , 149px 1492px 0 0 rgba(255,255,255, 0.911) , 1203px 1138px 0 0 rgba(255,255,255, 0.964) , 781px 1584px 0 0 rgba(255,255,255, 0.465) , 1609px 1595px 0 0 rgba(255,255,255, 0.688) , 447px 1655px 0 0 rgba(255,255,255, 0.166) , 914px 1153px 0 0 rgba(255,255,255, 0.085) , 600px 1058px 0 0 rgba(255,255,255, 0.821) , 804px 505px 0 0 rgba(255,255,255, 0.608) , 1506px 584px 0 0 rgba(255,255,255, 0.618) , 587px 1290px 0 0 rgba(255,255,255, 0.071) , 258px 600px 0 0 rgba(255,255,255, 0.243) , 328px 395px 0 0 rgba(255,255,255, 0.065) , 846px 783px 0 0 rgba(255,255,255, 0.995) , 1138px 1294px 0 0 rgba(255,255,255, 0.703) , 1668px 633px 0 0 rgba(255,255,255, 0.27) , 337px 103px 0 0 rgba(255,255,255, 0.202) , 132px 986px 0 0 rgba(255,255,255, 0.726) , 414px 757px 0 0 rgba(255,255,255, 0.752) , 8px 1311px 0 0 rgba(255,255,255, 0.307) , 1791px 910px 0 0 rgba(255,255,255, 0.346) , 844px 216px 0 0 rgba(255,255,255, 0.156) , 1547px 1723px 0 0 rgba(255,255,255, 0.73) , 1187px 398px 0 0 rgba(255,255,255, 0.698) , 1550px 1520px 0 0 rgba(255,255,255, 0.462) , 1346px 655px 0 0 rgba(255,255,255, 0.58) , 668px 770px 0 0 rgba(255,255,255, 0.422) , 1774px 1435px 0 0 rgba(255,255,255, 0.089) , 693px 1061px 0 0 rgba(255,255,255, 0.893) , 132px 1689px 0 0 rgba(255,255,255, 0.937) , 894px 1561px 0 0 rgba(255,255,255, 0.88) , 906px 1706px 0 0 rgba(255,255,255, 0.567) , 1140px 297px 0 0 rgba(255,255,255, 0.358) , 13px 1288px 0 0 rgba(255,255,255, 0.464) , 1744px 423px 0 0 rgba(255,255,255, 0.845) , 119px 1548px 0 0 rgba(255,255,255, 0.769) , 1249px 1321px 0 0 rgba(255,255,255, 0.29) , 123px 795px 0 0 rgba(255,255,255, 0.597) , 390px 1542px 0 0 rgba(255,255,255, 0.47) , 825px 667px 0 0 rgba(255,255,255, 0.049) , 1071px 875px 0 0 rgba(255,255,255, 0.06) , 1428px 1786px 0 0 rgba(255,255,255, 0.222) , 993px 696px 0 0 rgba(255,255,255, 0.399) , 1585px 247px 0 0 rgba(255,255,255, 0.094) , 1340px 1312px 0 0 rgba(255,255,255, 0.603) , 1640px 725px 0 0 rgba(255,255,255, 0.026) , 1161px 1397px 0 0 rgba(255,255,255, 0.222) , 966px 1132px 0 0 rgba(255,255,255, 0.69) , 1782px 1275px 0 0 rgba(255,255,255, 0.606) , 1117px 1533px 0 0 rgba(255,255,255, 0.248) , 1027px 959px 0 0 rgba(255,255,255, 0.46) , 459px 839px 0 0 rgba(255,255,255, 0.98) , 1192px 265px 0 0 rgba(255,255,255, 0.523) , 175px 501px 0 0 rgba(255,255,255, 0.371) , 626px 19px 0 0 rgba(255,255,255, 0.246) , 46px 1173px 0 0 rgba(255,255,255, 0.124) , 573px 925px 0 0 rgba(255,255,255, 0.621) , 1px 283px 0 0 rgba(255,255,255, 0.943) , 778px 1213px 0 0 rgba(255,255,255, 0.128) , 435px 593px 0 0 rgba(255,255,255, 0.378) , 32px 394px 0 0 rgba(255,255,255, 0.451) , 1019px 1055px 0 0 rgba(255,255,255, 0.685) , 1423px 1233px 0 0 rgba(255,255,255, 0.354) , 494px 841px 0 0 rgba(255,255,255, 0.322) , 667px 194px 0 0 rgba(255,255,255, 0.655) , 1671px 195px 0 0 rgba(255,255,255, 0.502) , 403px 1710px 0 0 rgba(255,255,255, 0.623) , 665px 1597px 0 0 rgba(255,255,255, 0.839) , 61px 1742px 0 0 rgba(255,255,255, 0.566) , 1490px 1654px 0 0 rgba(255,255,255, 0.646) , 1361px 1604px 0 0 rgba(255,255,255, 0.101) , 1191px 1023px 0 0 rgba(255,255,255, 0.881) , 550px 378px 0 0 rgba(255,255,255, 0.573) , 1332px 1234px 0 0 rgba(255,255,255, 0.922) , 760px 1205px 0 0 rgba(255,255,255, 0.992) , 1506px 1328px 0 0 rgba(255,255,255, 0.723) , 1126px 813px 0 0 rgba(255,255,255, 0.549) , 67px 240px 0 0 rgba(255,255,255, 0.901) , 125px 1301px 0 0 rgba(255,255,255, 0.464) , 643px 391px 0 0 rgba(255,255,255, 0.589) , 1114px 1756px 0 0 rgba(255,255,255, 0.321) , 1602px 699px 0 0 rgba(255,255,255, 0.274) , 510px 393px 0 0 rgba(255,255,255, 0.185) , 171px 1217px 0 0 rgba(255,255,255, 0.932) , 1202px 1362px 0 0 rgba(255,255,255, 0.726) , 1160px 1324px 0 0 rgba(255,255,255, 0.867) , 121px 319px 0 0 rgba(255,255,255, 0.992) , 1474px 835px 0 0 rgba(255,255,255, 0.89) , 357px 1213px 0 0 rgba(255,255,255, 0.91) , 783px 976px 0 0 rgba(255,255,255, 0.941) , 750px 1599px 0 0 rgba(255,255,255, 0.515) , 323px 450px 0 0 rgba(255,255,255, 0.966) , 1078px 282px 0 0 rgba(255,255,255, 0.947) , 1164px 46px 0 0 rgba(255,255,255, 0.296) , 1792px 705px 0 0 rgba(255,255,255, 0.485) , 880px 1287px 0 0 rgba(255,255,255, 0.894) , 60px 1402px 0 0 rgba(255,255,255, 0.816) , 752px 894px 0 0 rgba(255,255,255, 0.803) , 285px 1535px 0 0 rgba(255,255,255, 0.93) , 1528px 401px 0 0 rgba(255,255,255, 0.727) , 651px 1767px 0 0 rgba(255,255,255, 0.146) , 1498px 1190px 0 0 rgba(255,255,255, 0.042) , 394px 1786px 0 0 rgba(255,255,255, 0.159) , 1318px 9px 0 0 rgba(255,255,255, 0.575) , 1699px 1675px 0 0 rgba(255,255,255, 0.511) , 82px 986px 0 0 rgba(255,255,255, 0.906) , 940px 970px 0 0 rgba(255,255,255, 0.562) , 1624px 259px 0 0 rgba(255,255,255, 0.537) , 1782px 222px 0 0 rgba(255,255,255, 0.259) , 1572px 1725px 0 0 rgba(255,255,255, 0.716) , 1080px 1557px 0 0 rgba(255,255,255, 0.245) , 1727px 648px 0 0 rgba(255,255,255, 0.471) , 899px 231px 0 0 rgba(255,255,255, 0.445) , 1061px 1074px 0 0 rgba(255,255,255, 0.079) , 556px 478px 0 0 rgba(255,255,255, 0.524) , 343px 359px 0 0 rgba(255,255,255, 0.162) , 711px 1254px 0 0 rgba(255,255,255, 0.323) , 1335px 242px 0 0 rgba(255,255,255, 0.936) , 933px 39px 0 0 rgba(255,255,255, 0.784) , 1629px 908px 0 0 rgba(255,255,255, 0.289) , 1800px 229px 0 0 rgba(255,255,255, 0.399) , 1589px 926px 0 0 rgba(255,255,255, 0.709) , 976px 694px 0 0 rgba(255,255,255, 0.855) , 1163px 1240px 0 0 rgba(255,255,255, 0.754) , 1662px 1784px 0 0 rgba(255,255,255, 0.088) , 656px 1388px 0 0 rgba(255,255,255, 0.688) , 1190px 1100px 0 0 rgba(255,255,255, 0.769) , 33px 392px 0 0 rgba(255,255,255, 0.301) , 56px 1405px 0 0 rgba(255,255,255, 0.969) , 1491px 118px 0 0 rgba(255,255,255, 0.991) , 1216px 997px 0 0 rgba(255,255,255, 0.727) , 1617px 712px 0 0 rgba(255,255,255, 0.45) , 163px 553px 0 0 rgba(255,255,255, 0.977) , 103px 140px 0 0 rgba(255,255,255, 0.916) , 1099px 1404px 0 0 rgba(255,255,255, 0.167) , 1423px 587px 0 0 rgba(255,255,255, 0.792) , 1797px 309px 0 0 rgba(255,255,255, 0.526) , 381px 141px 0 0 rgba(255,255,255, 0.005) , 1214px 802px 0 0 rgba(255,255,255, 0.887) , 211px 829px 0 0 rgba(255,255,255, 0.72) , 1103px 1507px 0 0 rgba(255,255,255, 0.642) , 244px 1231px 0 0 rgba(255,255,255, 0.184) , 118px 1747px 0 0 rgba(255,255,255, 0.475) , 183px 1293px 0 0 rgba(255,255,255, 0.148) , 911px 1362px 0 0 rgba(255,255,255, 0.073) , 817px 457px 0 0 rgba(255,255,255, 0.459) , 756px 18px 0 0 rgba(255,255,255, 0.544) , 481px 1118px 0 0 rgba(255,255,255, 0.878) , 380px 138px 0 0 rgba(255,255,255, 0.132) , 320px 646px 0 0 rgba(255,255,255, 0.04) , 1724px 1716px 0 0 rgba(255,255,255, 0.381) , 978px 1269px 0 0 rgba(255,255,255, 0.431) , 1530px 255px 0 0 rgba(255,255,255, 0.31) , 664px 204px 0 0 rgba(255,255,255, 0.913) , 474px 703px 0 0 rgba(255,255,255, 0.832) , 1722px 1204px 0 0 rgba(255,255,255, 0.356) , 1453px 821px 0 0 rgba(255,255,255, 0.195) , 730px 1468px 0 0 rgba(255,255,255, 0.696) , 928px 1610px 0 0 rgba(255,255,255, 0.894) , 1036px 304px 0 0 rgba(255,255,255, 0.696) , 1590px 172px 0 0 rgba(255,255,255, 0.729) , 249px 1590px 0 0 rgba(255,255,255, 0.277) , 357px 81px 0 0 rgba(255,255,255, 0.526) , 726px 1261px 0 0 rgba(255,255,255, 0.149) , 643px 946px 0 0 rgba(255,255,255, 0.005) , 1263px 995px 0 0 rgba(255,255,255, 0.124) , 1564px 1107px 0 0 rgba(255,255,255, 0.789) , 388px 83px 0 0 rgba(255,255,255, 0.498) , 715px 681px 0 0 rgba(255,255,255, 0.655) , 1618px 1624px 0 0 rgba(255,255,255, 0.63) , 1423px 1576px 0 0 rgba(255,255,255, 0.52) , 564px 1786px 0 0 rgba(255,255,255, 0.482) , 1066px 735px 0 0 rgba(255,255,255, 0.276) , 714px 1179px 0 0 rgba(255,255,255, 0.395) , 967px 1006px 0 0 rgba(255,255,255, 0.923) , 1136px 1790px 0 0 rgba(255,255,255, 0.801) , 215px 1690px 0 0 rgba(255,255,255, 0.957) , 1500px 1338px 0 0 rgba(255,255,255, 0.541) , 1679px 1065px 0 0 rgba(255,255,255, 0.925) , 426px 1489px 0 0 rgba(255,255,255, 0.193) , 1273px 853px 0 0 rgba(255,255,255, 0.317) , 665px 1189px 0 0 rgba(255,255,255, 0.512) , 520px 552px 0 0 rgba(255,255,255, 0.925) , 253px 438px 0 0 rgba(255,255,255, 0.588) , 369px 1354px 0 0 rgba(255,255,255, 0.889) , 749px 205px 0 0 rgba(255,255,255, 0.243) , 820px 145px 0 0 rgba(255,255,255, 0.207) , 1739px 228px 0 0 rgba(255,255,255, 0.267) , 392px 495px 0 0 rgba(255,255,255, 0.504) , 721px 1044px 0 0 rgba(255,255,255, 0.823) , 833px 912px 0 0 rgba(255,255,255, 0.222) , 865px 1499px 0 0 rgba(255,255,255, 0.003) , 313px 756px 0 0 rgba(255,255,255, 0.727) , 439px 1187px 0 0 rgba(255,255,255, 0.572) , 6px 1238px 0 0 rgba(255,255,255, 0.676) , 1567px 11px 0 0 rgba(255,255,255, 0.701) , 1216px 757px 0 0 rgba(255,255,255, 0.87) , 916px 588px 0 0 rgba(255,255,255, 0.565) , 831px 215px 0 0 rgba(255,255,255, 0.597) , 1289px 697px 0 0 rgba(255,255,255, 0.964) , 307px 34px 0 0 rgba(255,255,255, 0.462) , 3px 1685px 0 0 rgba(255,255,255, 0.464) , 1115px 1421px 0 0 rgba(255,255,255, 0.303) , 1451px 473px 0 0 rgba(255,255,255, 0.142) , 1374px 1205px 0 0 rgba(255,255,255, 0.086) , 1564px 317px 0 0 rgba(255,255,255, 0.773) , 304px 1127px 0 0 rgba(255,255,255, 0.653) , 446px 214px 0 0 rgba(255,255,255, 0.135) , 1541px 459px 0 0 rgba(255,255,255, 0.725) , 1387px 880px 0 0 rgba(255,255,255, 0.157) , 1172px 224px 0 0 rgba(255,255,255, 0.088) , 1420px 637px 0 0 rgba(255,255,255, 0.916) , 1385px 932px 0 0 rgba(255,255,255, 0.225) , 174px 1472px 0 0 rgba(255,255,255, 0.649) , 252px 750px 0 0 rgba(255,255,255, 0.277) , 825px 1042px 0 0 rgba(255,255,255, 0.707) , 840px 703px 0 0 rgba(255,255,255, 0.948) , 1478px 1800px 0 0 rgba(255,255,255, 0.151) , 95px 1303px 0 0 rgba(255,255,255, 0.332) , 1198px 740px 0 0 rgba(255,255,255, 0.443) , 141px 312px 0 0 rgba(255,255,255, 0.04) , 291px 729px 0 0 rgba(255,255,255, 0.284) , 1209px 1506px 0 0 rgba(255,255,255, 0.741) , 1188px 307px 0 0 rgba(255,255,255, 0.141) , 958px 41px 0 0 rgba(255,255,255, 0.858) , 1311px 1484px 0 0 rgba(255,255,255, 0.097) , 846px 1153px 0 0 rgba(255,255,255, 0.862) , 1238px 1376px 0 0 rgba(255,255,255, 0.071) , 1499px 342px 0 0 rgba(255,255,255, 0.719) , 640px 833px 0 0 rgba(255,255,255, 0.966) , 712px 545px 0 0 rgba(255,255,255, 0.194) , 1655px 1542px 0 0 rgba(255,255,255, 0.82) , 616px 353px 0 0 rgba(255,255,255, 0.871) , 1591px 1631px 0 0 rgba(255,255,255, 0.61) , 1664px 591px 0 0 rgba(255,255,255, 0.35) , 934px 454px 0 0 rgba(255,255,255, 0.58) , 1175px 477px 0 0 rgba(255,255,255, 0.966) , 299px 914px 0 0 rgba(255,255,255, 0.839) , 534px 243px 0 0 rgba(255,255,255, 0.194) , 773px 1135px 0 0 rgba(255,255,255, 0.42) , 1696px 1472px 0 0 rgba(255,255,255, 0.552) , 125px 523px 0 0 rgba(255,255,255, 0.591) , 1195px 382px 0 0 rgba(255,255,255, 0.904) , 1609px 1374px 0 0 rgba(255,255,255, 0.579) , 843px 82px 0 0 rgba(255,255,255, 0.072) , 1604px 451px 0 0 rgba(255,255,255, 0.545) , 1322px 190px 0 0 rgba(255,255,255, 0.034) , 528px 228px 0 0 rgba(255,255,255, 0.146) , 1470px 1169px 0 0 rgba(255,255,255, 0.912) , 502px 1350px 0 0 rgba(255,255,255, 0.594) , 1031px 298px 0 0 rgba(255,255,255, 0.368) , 1100px 1427px 0 0 rgba(255,255,255, 0.79) , 979px 1105px 0 0 rgba(255,255,255, 0.973) , 643px 1184px 0 0 rgba(255,255,255, 0.813) , 1636px 1701px 0 0 rgba(255,255,255, 0.013) , 1004px 245px 0 0 rgba(255,255,255, 0.412) , 680px 740px 0 0 rgba(255,255,255, 0.967) , 1599px 562px 0 0 rgba(255,255,255, 0.66) , 256px 1617px 0 0 rgba(255,255,255, 0.463) , 314px 1092px 0 0 rgba(255,255,255, 0.734) , 870px 900px 0 0 rgba(255,255,255, 0.512) , 530px 60px 0 0 rgba(255,255,255, 0.198) , 1786px 896px 0 0 rgba(255,255,255, 0.392) , 636px 212px 0 0 rgba(255,255,255, 0.997) , 672px 540px 0 0 rgba(255,255,255, 0.632) , 1118px 1649px 0 0 rgba(255,255,255, 0.377) , 433px 647px 0 0 rgba(255,255,255, 0.902) , 1200px 1737px 0 0 rgba(255,255,255, 0.262) , 1258px 143px 0 0 rgba(255,255,255, 0.729) , 1603px 1364px 0 0 rgba(255,255,255, 0.192) , 66px 1756px 0 0 rgba(255,255,255, 0.681) , 946px 263px 0 0 rgba(255,255,255, 0.105) , 1216px 1082px 0 0 rgba(255,255,255, 0.287) , 6px 1143px 0 0 rgba(255,255,255, 0.017) , 1631px 126px 0 0 rgba(255,255,255, 0.449) , 357px 1565px 0 0 rgba(255,255,255, 0.163) , 1752px 261px 0 0 rgba(255,255,255, 0.423) , 1247px 1631px 0 0 rgba(255,255,255, 0.312) , 320px 671px 0 0 rgba(255,255,255, 0.695) , 1375px 596px 0 0 rgba(255,255,255, 0.856) , 1456px 1340px 0 0 rgba(255,255,255, 0.564) , 447px 1044px 0 0 rgba(255,255,255, 0.623) , 1732px 447px 0 0 rgba(255,255,255, 0.216) , 174px 1509px 0 0 rgba(255,255,255, 0.398) , 16px 861px 0 0 rgba(255,255,255, 0.904) , 878px 1296px 0 0 rgba(255,255,255, 0.205) , 1725px 1483px 0 0 rgba(255,255,255, 0.704) , 255px 48px 0 0 rgba(255,255,255, 0.7) , 610px 1669px 0 0 rgba(255,255,255, 0.865) , 1044px 1251px 0 0 rgba(255,255,255, 0.98) , 884px 862px 0 0 rgba(255,255,255, 0.198) , 986px 545px 0 0 rgba(255,255,255, 0.379) , 1620px 217px 0 0 rgba(255,255,255, 0.159) , 383px 1763px 0 0 rgba(255,255,255, 0.518) , 595px 974px 0 0 rgba(255,255,255, 0.347) , 359px 14px 0 0 rgba(255,255,255, 0.863) , 95px 1385px 0 0 rgba(255,255,255, 0.011) , 411px 1030px 0 0 rgba(255,255,255, 0.038) , 345px 789px 0 0 rgba(255,255,255, 0.771) , 421px 460px 0 0 rgba(255,255,255, 0.133) , 972px 1160px 0 0 rgba(255,255,255, 0.342) , 597px 1061px 0 0 rgba(255,255,255, 0.781) , 1017px 1092px 0 0 rgba(255,255,255, 0.437); }\n        .wrapper { margin: 0 auto; max-width: 64rem; padding: 0 20px; position: relative; }\n        .logo { display: flex; margin-top: 45px; }\n        .logo svg { height: 48px; width: 48px; margin-right: 15px; }\n        .logo h1 { font-size: 32px; line-height: 1; margin: 0; }\n        .logo h1 small { display: block; font-size: 18px; }\n        .info { padding-bottom: 60px; }\n        .info ul { list-style: none; margin: 30px 0; padding: 0; }\n        .info li { display: flex; }\n        .info li + li { margin-top: 30px; }\n        .info svg { height: 20px; width: 20px; margin-right: 10px; flex-shrink: 0; }\n        .info code { display: block; font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace; font-size: .9em; margin-top: 5px; }\n        .info .next-step { background: rgba(255, 255, 255, 0.2); border-radius: 4px; line-height: 1.5; margin: 0 0 20px; padding: 10px 15px; }\n        .info .next-step strong { display: block; text-transform: uppercase; font-size: 90%; }\n        .info .next-step svg { display: none; }\n        .waves { color: #3a3a52; position: absolute; bottom: -5px; left: 0; right: 0; width: 100% }\n        main article { padding: 30px 0 0; }\n        main h2 { align-items: center; display: flex; font-size: 18px; font-weight: 600; margin: 0; }\n        main h2 span { display: inline-flex; }\n        main h2 svg { height: 28px; width: 28px; margin-right: 10px; }\n        main article section + section { margin-top: 45px; }\n        main article section ul { padding-left: 23px; }\n        main article section li + li { margin-top: 15px; }\n        header .wrapper, header .waves, .sf-toolbar {  z-index: 10; }\n\n        @media (min-width: 768px) {\n            @keyframes fade-in { 0% { opacity: 0; } 100% { opacity: 1; } }\n            .sf-toolbar { opacity: 0; animation: fade-in 1s .2s forwards; position: relative; z-index: 99999; }\n            @media (prefers-reduced-motion) {\n                .sf-toolbar { animation: none !important; opacity: 1; }\n            }\n\n            body { font-size: 18px; }\n            .wrapper { padding: 0 30px; }\n            .logo { margin-top: 75px; }\n            .logo svg { height: 72px; width: 72px; margin-right: 30px; }\n            .logo h1 { font-size: 48px; }\n            .logo h1 small { font-size: 24px; }\n            .info ul { margin: 45px 0; padding-left: 15px; }\n            .info li + li { margin-top: 35px; }\n            .info svg { height: 28px; width: 28px; margin-right: 13px; position: relative; top: -2px; }\n            .info code { margin-top: 10px; }\n            .info .next-step { display: flex; align-items: center; margin: 0 0 45px; padding: 15px; }\n            .info .next-step svg { display: inline-flex; margin: 0 10px; top: 0; }\n            main article nav { display: flex; justify-content: space-between; padding-top: 45px; }\n            main article section + section { margin-top: 0; }\n            main h2 { font-size: 21px; }\n            main h2 svg { height: 36px; width: 36px; margin-right: 15px; }\n            main article section ul { padding-left: 28px; }\n            main article section li + li { margin-top: 20px; }\n        }\n\n        @media (min-width: 1280px) {\n            body { font-size: 20px; }\n            .logo { margin-top: 105px; }\n            .logo svg { height: 96px; width: 96px; margin-right: 45px; }\n            .logo h1 { font-size: 64px; }\n            .logo h1 small { font-size: 36px; }\n            .info ul { margin: 60px 0; padding-left: 30px; }\n            .info li + li { margin-top: 45px; }\n            .info svg { height: 32px; width: 32px; margin-right: 15px; position: relative; top: -4px; }\n            .info .next-step { padding: 15px 30px; margin: 0 0 60px; }\n            .info .next-step svg { margin: 0 15px; }\n            main article { padding-top: 60px; }\n            main h2 { align-items: flex-start; flex-direction: column; font-size: 24px; }\n            main h2 svg { display: block; height: 48px; width: 48px; margin-bottom: 10px; margin-left: -4px; }\n            main article section ul { padding-left: 20px; }\n            main article section li + li { margin-top: 25px; }\n        }\n    </style>\n</head>\n<body>\n    <header>\n        <div class=\"wrapper\">\n            <section class=\"logo\">\n                <?php echo $renderSymfonyLogoSvg; ?>\n                <h1>\n                    <small>Welcome to</small>\n                    <span translate=\"no\" class=\"notranslate\">Symfony</span> <?php echo explode('.', $version, 2)[0]; ?>\n                </h1>\n            </section>\n\n            <section class=\"info\">\n                <ul>\n                    <li>\n                        <?php echo $renderBoxIconSvg; ?>\n                        <span>You are using Symfony <strong><?php echo $version; ?></strong> version</span>\n                    </li>\n\n                    <li>\n                        <?php echo $renderFolderIconSvg; ?>\n                        <span>Your application is ready at: <code translate=\"no\" class=\"notranslate project_dir_path\"><?php echo $projectDir; ?></code></span>\n                    </li>\n\n                    <li>\n                        <?php echo $renderInfoIconSvg; ?>\n                        <span>You are seeing this page because the homepage URL is not configured and <a target=\"_blank\" href=\"https://symfony.com/doc/<?php echo $docVersion; ?>/debug-mode\">debug mode</a> is enabled.</span>\n                    </li>\n                </ul>\n\n                <p class=\"next-step\" role=\"note\">\n                    <strong>Next Step</strong>\n                    <?php echo $renderNextStepIconSvg; ?>\n                    <span>\n                        <a target=\"_blank\" href=\"https://symfony.com/doc/<?php echo $docVersion; ?>/page_creation.html\">Create your first page</a>\n                        to replace this placeholder page.\n                    </span>\n                </p>\n            </section>\n        </div>\n\n        <section class=\"waves\" aria-hidden=\"true\" role=\"separator\">\n            <?php echo $renderWavesSvg; ?>\n        </section>\n    </header>\n\n    <main>\n        <div class=\"wrapper\">\n            <article>\n                <nav>\n                    <section>\n                        <h2>\n                            <span><?php echo $renderLearnIconSvg; ?></span>\n                            Learn\n                        </h2>\n                        <ul>\n                            <li>\n                                <a target=\"_blank\" href=\"https://symfony.com/doc/<?php echo $docVersion; ?>\">Read Symfony Docs</a>\n                            </li>\n                            <li>\n                                <a target=\"_blank\" href=\"https://symfonycasts.com/screencast/symfony\">Watch Symfony Screencast</a>\n                            </li>\n                            <li>\n                                <a target=\"_blank\" href=\"https://symfony.com/book\">Read Symfony Book</a>\n                            </li>\n                        </ul>\n                    </section>\n\n                    <section>\n                        <h2>\n                            <span><?php echo $renderCommunityIconSvg; ?></span>\n                            Community & Support\n                        </h2>\n                        <ul>\n                            <li>\n                                <a target=\"_blank\" href=\"https://symfony.com/support\">Symfony Support</a>\n                            </li>\n                            <li>\n                                <a target=\"_blank\" href=\"https://symfony.com/community\">Join the Symfony Community</a>\n                            </li>\n                            <li>\n                                <a target=\"_blank\" href=\"https://symfony.com/doc/current/contributing/index.html\">Contribute to Symfony</a>\n                            </li>\n                        </ul>\n                    </section>\n\n                    <section>\n                        <h2>\n                            <span><?php echo $renderUpdatesIconSvg; ?></span>\n                            Stay Updated\n                        </h2>\n                        <ul>\n                            <li>\n                                <a target=\"_blank\" href=\"https://symfony.com/blog/\">Symfony Blog</a>\n                            </li>\n                            <li>\n                                <a target=\"_blank\" href=\"https://symfony.com/community#interact\">Follow Symfony</a>\n                            </li>\n                            <li>\n                                <a target=\"_blank\" href=\"https://symfony.com/events/\">Attend Symfony Events</a>\n                            </li>\n                        </ul>\n                    </section>\n                </nav>\n            </article>\n        </div>\n    </main>\n</body>\n</html>\n"
  },
  {
    "path": "TerminableInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\n\n/**\n * Terminable extends the Kernel request/response cycle with dispatching a post\n * response event after sending the response and before shutting down the kernel.\n *\n * @author Jordi Boggiano <j.boggiano@seld.be>\n * @author Pierre Minnieur <pierre.minnieur@sensiolabs.de>\n */\ninterface TerminableInterface\n{\n    /**\n     * Terminates a request/response cycle.\n     *\n     * Should be called after sending the response and before shutting down the kernel.\n     */\n    public function terminate(Request $request, Response $response): void;\n}\n"
  },
  {
    "path": "Tests/Attribute/WithLogLevelTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Attribute;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LogLevel;\nuse Symfony\\Component\\HttpKernel\\Attribute\\WithLogLevel;\n\n/**\n * @author Dejan Angelov <angelovdejan@protonmail.com>\n */\nclass WithLogLevelTest extends TestCase\n{\n    public function testWithValidLogLevel()\n    {\n        $logLevel = LogLevel::NOTICE;\n\n        $attribute = new WithLogLevel($logLevel);\n\n        $this->assertSame($logLevel, $attribute->level);\n    }\n\n    public function testWithInvalidLogLevel()\n    {\n        $this->expectException(\\InvalidArgumentException::class);\n        $this->expectExceptionMessage('Invalid log level \"invalid\".');\n\n        new WithLogLevel('invalid');\n    }\n}\n"
  },
  {
    "path": "Tests/Bundle/BundleTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Bundle;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Config\\Loader\\LoaderInterface;\nuse Symfony\\Component\\HttpKernel\\Bundle\\Bundle;\nuse Symfony\\Component\\HttpKernel\\Kernel;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\BundleCompilerPass\\BundleAsCompilerPassBundle;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\ExtensionPresentBundle\\ExtensionPresentBundle;\n\nclass BundleTest extends TestCase\n{\n    public function testGetContainerExtension()\n    {\n        $bundle = new ExtensionPresentBundle();\n\n        $this->assertInstanceOf(\n            'Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\ExtensionPresentBundle\\DependencyInjection\\ExtensionPresentExtension',\n            $bundle->getContainerExtension()\n        );\n    }\n\n    public function testBundleNameIsGuessedFromClass()\n    {\n        $bundle = new GuessedNameBundle();\n\n        $this->assertSame('Symfony\\Component\\HttpKernel\\Tests\\Bundle', $bundle->getNamespace());\n        $this->assertSame('GuessedNameBundle', $bundle->getName());\n    }\n\n    public function testBundleNameCanBeExplicitlyProvided()\n    {\n        $bundle = new NamedBundle();\n\n        $this->assertSame('ExplicitlyNamedBundle', $bundle->getName());\n        $this->assertSame('Symfony\\Component\\HttpKernel\\Tests\\Bundle', $bundle->getNamespace());\n        $this->assertSame('ExplicitlyNamedBundle', $bundle->getName());\n    }\n\n    public function testBundleAsCompilerPass()\n    {\n        $kernel = new class('test', true) extends Kernel {\n            public function registerBundles(): iterable\n            {\n                yield new BundleAsCompilerPassBundle();\n            }\n\n            public function registerContainerConfiguration(LoaderInterface $loader): void\n            {\n            }\n\n            public function getProjectDir(): string\n            {\n                return sys_get_temp_dir().'/bundle_as_compiler_pass';\n            }\n        };\n\n        $kernel->boot();\n\n        $this->assertTrue($kernel->getContainer()->has('foo'));\n    }\n}\n\nclass NamedBundle extends Bundle\n{\n    public function __construct()\n    {\n        $this->name = 'ExplicitlyNamedBundle';\n    }\n}\n\nclass GuessedNameBundle extends Bundle\n{\n}\n"
  },
  {
    "path": "Tests/CacheClearer/ChainCacheClearerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\CacheClearer;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpKernel\\CacheClearer\\CacheClearerInterface;\nuse Symfony\\Component\\HttpKernel\\CacheClearer\\ChainCacheClearer;\n\nclass ChainCacheClearerTest extends TestCase\n{\n    protected static string $cacheDir;\n\n    public static function setUpBeforeClass(): void\n    {\n        self::$cacheDir = tempnam(sys_get_temp_dir(), 'sf_cache_clearer_dir');\n    }\n\n    public static function tearDownAfterClass(): void\n    {\n        @unlink(self::$cacheDir);\n    }\n\n    public function testInjectClearersInConstructor()\n    {\n        $clearer = $this->createMock(CacheClearerInterface::class);\n        $clearer\n            ->expects($this->once())\n            ->method('clear');\n\n        $chainClearer = new ChainCacheClearer([$clearer]);\n        $chainClearer->clear(self::$cacheDir);\n    }\n}\n"
  },
  {
    "path": "Tests/CacheClearer/Psr6CacheClearerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\CacheClearer;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Cache\\CacheItemPoolInterface;\nuse Symfony\\Component\\HttpKernel\\CacheClearer\\Psr6CacheClearer;\n\nclass Psr6CacheClearerTest extends TestCase\n{\n    public function testClearPoolsInjectedInConstructor()\n    {\n        $pool = $this->createMock(CacheItemPoolInterface::class);\n        $pool\n            ->expects($this->once())\n            ->method('clear');\n\n        (new Psr6CacheClearer(['pool' => $pool]))->clear('');\n    }\n\n    public function testClearPool()\n    {\n        $pool = $this->createMock(CacheItemPoolInterface::class);\n        $pool\n            ->expects($this->once())\n            ->method('clear')\n            ->willReturn(true)\n        ;\n\n        $this->assertTrue((new Psr6CacheClearer(['pool' => $pool]))->clearPool('pool'));\n    }\n\n    public function testClearPoolThrowsExceptionOnUnreferencedPool()\n    {\n        $this->expectException(\\InvalidArgumentException::class);\n        $this->expectExceptionMessage('Cache pool not found: \"unknown\"');\n        (new Psr6CacheClearer())->clearPool('unknown');\n    }\n}\n"
  },
  {
    "path": "Tests/CacheWarmer/CacheWarmerAggregateTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\CacheWarmer;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Console\\Style\\SymfonyStyle;\nuse Symfony\\Component\\HttpKernel\\CacheWarmer\\CacheWarmerAggregate;\nuse Symfony\\Component\\HttpKernel\\CacheWarmer\\CacheWarmerInterface;\n\nclass CacheWarmerAggregateTest extends TestCase\n{\n    public function testInjectWarmersUsingConstructor()\n    {\n        $warmer = $this->createMock(CacheWarmerInterface::class);\n        $warmer\n            ->expects($this->once())\n            ->method('warmUp');\n        $aggregate = new CacheWarmerAggregate([$warmer]);\n        $aggregate->warmUp(__DIR__);\n    }\n\n    public function testWarmupDoesCallWarmupOnOptionalWarmersWhenEnableOptionalWarmersIsEnabled()\n    {\n        $warmer = $this->createMock(CacheWarmerInterface::class);\n        $warmer\n            ->expects($this->never())\n            ->method('isOptional');\n        $warmer\n            ->expects($this->once())\n            ->method('warmUp');\n\n        $aggregate = new CacheWarmerAggregate([$warmer]);\n        $aggregate->enableOptionalWarmers();\n        $aggregate->warmUp(__DIR__);\n    }\n\n    public function testWarmupDoesNotCallWarmupOnOptionalWarmersWhenEnableOptionalWarmersIsNotEnabled()\n    {\n        $warmer = $this->createMock(CacheWarmerInterface::class);\n        $warmer\n            ->expects($this->once())\n            ->method('isOptional')\n            ->willReturn(true);\n        $warmer\n            ->expects($this->never())\n            ->method('warmUp');\n\n        $aggregate = new CacheWarmerAggregate([$warmer]);\n        $aggregate->warmUp(__DIR__);\n    }\n\n    public function testWarmupReturnsFilesOrClasses()\n    {\n        $warmer = $this->createMock(CacheWarmerInterface::class);\n        $warmer\n            ->expects($this->never())\n            ->method('isOptional');\n        $warmer\n            ->expects($this->once())\n            ->method('warmUp')\n            ->willReturn([__CLASS__, __FILE__]);\n\n        $aggregate = new CacheWarmerAggregate([$warmer]);\n        $aggregate->enableOptionalWarmers();\n\n        $this->assertSame([__CLASS__, __FILE__], $aggregate->warmUp(__DIR__));\n    }\n\n    public function testWarmupChecksInvalidFiles()\n    {\n        $warmer = $this->createMock(CacheWarmerInterface::class);\n        $warmer\n            ->expects($this->never())\n            ->method('isOptional');\n        $warmer\n            ->expects($this->once())\n            ->method('warmUp')\n            ->willReturn([self::class, __DIR__]);\n\n        $aggregate = new CacheWarmerAggregate([$warmer]);\n        $aggregate->enableOptionalWarmers();\n\n        $this->expectException(\\LogicException::class);\n        $aggregate->warmUp(__DIR__);\n    }\n\n    public function testWarmupPassBuildDir()\n    {\n        $warmer = $this->createMock(CacheWarmerInterface::class);\n        $warmer\n            ->expects($this->once())\n            ->method('warmUp')\n            ->with('cache_dir', 'build_dir');\n\n        $aggregate = new CacheWarmerAggregate([$warmer]);\n        $aggregate->enableOptionalWarmers();\n        $aggregate->warmUp('cache_dir', 'build_dir');\n    }\n\n    public function testWarmupOnOptionalWarmerPassBuildDir()\n    {\n        $warmer = $this->createMock(CacheWarmerInterface::class);\n        $warmer\n            ->expects($this->once())\n            ->method('isOptional')\n            ->willReturn(true);\n        $warmer\n            ->expects($this->once())\n            ->method('warmUp')\n            ->with('cache_dir', 'build_dir');\n\n        $aggregate = new CacheWarmerAggregate([$warmer]);\n        $aggregate->enableOnlyOptionalWarmers();\n        $aggregate->warmUp('cache_dir', 'build_dir');\n    }\n\n    public function testWarmupWhenDebugDisplaysWarmupDuration()\n    {\n        $warmer = $this->createMock(CacheWarmerInterface::class);\n        $io = $this->createMock(SymfonyStyle::class);\n\n        $io\n            ->expects($this->once())\n            ->method('isDebug')\n            ->willReturn(true)\n        ;\n\n        $io\n            ->expects($this->once())\n            ->method('info')\n            ->with($this->matchesRegularExpression('/\"(.+)\" completed in (.+)ms\\./'))\n        ;\n\n        $warmer\n            ->expects($this->once())\n            ->method('warmUp');\n\n        $aggregate = new CacheWarmerAggregate([$warmer]);\n        $aggregate->warmUp(__DIR__, null, $io);\n    }\n\n    public function testWarmupWhenNotDebugDoesntDisplayWarmupDuration()\n    {\n        $warmer = $this->createMock(CacheWarmerInterface::class);\n        $io = $this->createMock(SymfonyStyle::class);\n\n        $io\n            ->expects($this->once())\n            ->method('isDebug')\n            ->willReturn(false)\n        ;\n\n        $io\n            ->expects($this->never())\n            ->method('info')\n            ->with($this->matchesRegularExpression('/\"(.+)\" completed in (.+)ms\\./'))\n        ;\n\n        $warmer\n            ->expects($this->once())\n            ->method('warmUp');\n\n        $aggregate = new CacheWarmerAggregate([$warmer]);\n        $aggregate->warmUp(__DIR__, null, $io);\n    }\n}\n"
  },
  {
    "path": "Tests/CacheWarmer/CacheWarmerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\CacheWarmer;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpKernel\\CacheWarmer\\CacheWarmer;\n\nclass CacheWarmerTest extends TestCase\n{\n    protected static string $cacheFile;\n\n    public static function setUpBeforeClass(): void\n    {\n        self::$cacheFile = tempnam(sys_get_temp_dir(), 'sf_cache_warmer_dir');\n    }\n\n    public static function tearDownAfterClass(): void\n    {\n        @unlink(self::$cacheFile);\n    }\n\n    public function testWriteCacheFileCreatesTheFile()\n    {\n        $warmer = new TestCacheWarmer(self::$cacheFile);\n        $warmer->warmUp(\\dirname(self::$cacheFile));\n\n        $this->assertFileExists(self::$cacheFile);\n    }\n\n    public function testWriteNonWritableCacheFileThrowsARuntimeException()\n    {\n        $this->expectException(\\RuntimeException::class);\n        $nonWritableFile = '/this/file/is/very/probably/not/writable';\n        $warmer = new TestCacheWarmer($nonWritableFile);\n        $warmer->warmUp(\\dirname($nonWritableFile));\n    }\n}\n\nclass TestCacheWarmer extends CacheWarmer\n{\n    protected string $file;\n\n    public function __construct(string $file)\n    {\n        $this->file = $file;\n    }\n\n    public function warmUp(string $cacheDir, ?string $buildDir = null): array\n    {\n        $this->writeCacheFile($this->file, 'content');\n\n        return [];\n    }\n\n    public function isOptional(): bool\n    {\n        return false;\n    }\n}\n"
  },
  {
    "path": "Tests/Config/FileLocatorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Config;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpKernel\\Config\\FileLocator;\nuse Symfony\\Component\\HttpKernel\\KernelInterface;\n\nclass FileLocatorTest extends TestCase\n{\n    public function testLocate()\n    {\n        $kernel = $this->createMock(KernelInterface::class);\n        $kernel\n            ->expects($this->atLeastOnce())\n            ->method('locateResource')\n            ->with('@BundleName/some/path')\n            ->willReturn('/bundle-name/some/path');\n        $locator = new FileLocator($kernel);\n        $this->assertEquals('/bundle-name/some/path', $locator->locate('@BundleName/some/path'));\n\n        $kernel\n            ->expects($this->never())\n            ->method('locateResource');\n        $this->expectException(\\LogicException::class);\n        $locator->locate('/some/path');\n    }\n}\n"
  },
  {
    "path": "Tests/Controller/ArgumentResolver/BackedEnumValueResolverTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Controller\\ArgumentResolver;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\BackedEnumValueResolver;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\IntEnum;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Suit;\n\nclass BackedEnumValueResolverTest extends TestCase\n{\n    #[DataProvider('provideTestSupportsData')]\n    public function testSupports(Request $request, ArgumentMetadata $metadata, bool $expectedSupport)\n    {\n        $resolver = new BackedEnumValueResolver();\n\n        $this->assertCount((int) $expectedSupport, $resolver->resolve($request, $metadata));\n    }\n\n    public static function provideTestSupportsData(): iterable\n    {\n        yield 'unsupported type' => [\n            self::createRequest(['suit' => 'H']),\n            self::createArgumentMetadata('suit', \\stdClass::class),\n            false,\n        ];\n\n        yield 'supports from attributes' => [\n            self::createRequest(['suit' => 'H']),\n            self::createArgumentMetadata('suit', Suit::class),\n            true,\n        ];\n\n        yield 'with null attribute value' => [\n            self::createRequest(['suit' => null]),\n            self::createArgumentMetadata('suit', Suit::class),\n            true,\n        ];\n\n        yield 'without matching attribute' => [\n            self::createRequest(),\n            self::createArgumentMetadata('suit', Suit::class),\n            false,\n        ];\n\n        yield 'unsupported variadic' => [\n            self::createRequest(['suit' => ['H', 'S']]),\n            self::createArgumentMetadata(\n                'suit',\n                Suit::class,\n                variadic: true,\n            ),\n            false,\n        ];\n    }\n\n    #[DataProvider('provideTestResolveData')]\n    public function testResolve(Request $request, ArgumentMetadata $metadata, $expected)\n    {\n        $resolver = new BackedEnumValueResolver();\n        /** @var \\Generator $results */\n        $results = $resolver->resolve($request, $metadata);\n\n        self::assertSame($expected, $results);\n    }\n\n    public static function provideTestResolveData(): iterable\n    {\n        yield 'resolves from attributes' => [\n            self::createRequest(['suit' => 'H']),\n            self::createArgumentMetadata('suit', Suit::class),\n            [Suit::Hearts],\n        ];\n\n        yield 'with null attribute value' => [\n            self::createRequest(['suit' => null]),\n            self::createArgumentMetadata(\n                'suit',\n                Suit::class,\n            ),\n            [null],\n        ];\n\n        yield 'already resolved attribute value' => [\n            self::createRequest(['suit' => Suit::Hearts]),\n            self::createArgumentMetadata('suit', Suit::class),\n            [Suit::Hearts],\n        ];\n    }\n\n    public function testResolveThrowsNotFoundOnInvalidValue()\n    {\n        $resolver = new BackedEnumValueResolver();\n        $request = self::createRequest(['suit' => 'foo']);\n        $metadata = self::createArgumentMetadata('suit', Suit::class);\n\n        $this->expectException(NotFoundHttpException::class);\n        $this->expectExceptionMessage('Could not resolve the \"Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Suit $suit\" controller argument: \"foo\" is not a valid backing value for enum');\n\n        $resolver->resolve($request, $metadata);\n    }\n\n    public function testResolveThrowsOnUnexpectedType()\n    {\n        $resolver = new BackedEnumValueResolver();\n        $request = self::createRequest(['suit' => false]);\n        $metadata = self::createArgumentMetadata('suit', Suit::class);\n\n        $this->expectException(NotFoundHttpException::class);\n        $this->expectExceptionMessage('Could not resolve the \"Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Suit $suit\" controller argument: expecting an int or string, got \"bool\".');\n\n        $resolver->resolve($request, $metadata);\n    }\n\n    public function testResolveThrowsOnTypeError()\n    {\n        $resolver = new BackedEnumValueResolver();\n        $request = self::createRequest(['suit' => 'value']);\n        $metadata = self::createArgumentMetadata('suit', IntEnum::class);\n\n        $this->expectException(NotFoundHttpException::class);\n        $this->expectExceptionMessage('Could not resolve the \"Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\IntEnum $suit\" controller argument: Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\IntEnum::from(): Argument #1 ($value) must be of type int, string given');\n\n        $resolver->resolve($request, $metadata);\n    }\n\n    private static function createRequest(array $attributes = []): Request\n    {\n        return new Request([], [], $attributes);\n    }\n\n    private static function createArgumentMetadata(string $name, string $type, bool $variadic = false): ArgumentMetadata\n    {\n        return new ArgumentMetadata($name, $type, $variadic, false, null);\n    }\n}\n"
  },
  {
    "path": "Tests/Controller/ArgumentResolver/DateTimeValueResolverTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Controller\\ArgumentResolver;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Clock\\MockClock;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Attribute\\MapDateTime;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\DateTimeValueResolver;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;\n\nclass DateTimeValueResolverTest extends TestCase\n{\n    private readonly string $defaultTimezone;\n\n    protected function setUp(): void\n    {\n        $this->defaultTimezone = date_default_timezone_get();\n    }\n\n    protected function tearDown(): void\n    {\n        date_default_timezone_set($this->defaultTimezone);\n    }\n\n    public static function getTimeZones()\n    {\n        yield ['UTC', false];\n        yield ['Pacific/Honolulu', false];\n        yield ['America/Toronto', false];\n        yield ['UTC', true];\n        yield ['Pacific/Honolulu', true];\n        yield ['America/Toronto', true];\n    }\n\n    public static function getClasses()\n    {\n        yield [\\DateTimeInterface::class];\n        yield [\\DateTime::class];\n        yield [FooDateTime::class];\n    }\n\n    public function testUnsupportedArgument()\n    {\n        $resolver = new DateTimeValueResolver();\n\n        $argument = new ArgumentMetadata('dummy', \\stdClass::class, false, false, null);\n        $request = self::requestWithAttributes(['dummy' => 'now']);\n        $this->assertSame([], $resolver->resolve($request, $argument));\n    }\n\n    #[DataProvider('getTimeZones')]\n    public function testFullDate(string $timezone, bool $withClock)\n    {\n        date_default_timezone_set($withClock ? 'UTC' : $timezone);\n        $resolver = new DateTimeValueResolver($withClock ? new MockClock('now', $timezone) : null);\n\n        $argument = new ArgumentMetadata('dummy', \\DateTimeImmutable::class, false, false, null);\n        $request = self::requestWithAttributes(['dummy' => '2012-07-21 00:00:00']);\n\n        $results = $resolver->resolve($request, $argument);\n\n        $this->assertCount(1, $results);\n        $this->assertInstanceOf(\\DateTimeImmutable::class, $results[0]);\n        $this->assertSame($timezone, $results[0]->getTimezone()->getName(), 'Default timezone');\n        $this->assertEquals('2012-07-21 00:00:00', $results[0]->format('Y-m-d H:i:s'));\n    }\n\n    #[DataProvider('getTimeZones')]\n    public function testUnixTimestamp(string $timezone, bool $withClock)\n    {\n        date_default_timezone_set($withClock ? 'UTC' : $timezone);\n        $resolver = new DateTimeValueResolver($withClock ? new MockClock('now', $timezone) : null);\n\n        $argument = new ArgumentMetadata('dummy', \\DateTimeImmutable::class, false, false, null);\n        $request = self::requestWithAttributes(['dummy' => '989541720']);\n\n        $results = $resolver->resolve($request, $argument);\n\n        $this->assertCount(1, $results);\n        $this->assertInstanceOf(\\DateTimeImmutable::class, $results[0]);\n        $this->assertSame('+00:00', $results[0]->getTimezone()->getName(), 'Timestamps are UTC');\n        $this->assertEquals('2001-05-11 00:42:00', $results[0]->format('Y-m-d H:i:s'));\n    }\n\n    public function testNullableWithEmptyAttribute()\n    {\n        $resolver = new DateTimeValueResolver();\n\n        $argument = new ArgumentMetadata('dummy', \\DateTimeImmutable::class, false, false, null, true);\n        $request = self::requestWithAttributes(['dummy' => '']);\n\n        $results = $resolver->resolve($request, $argument);\n\n        $this->assertCount(1, $results);\n        $this->assertNull($results[0]);\n    }\n\n    /**\n     * @param class-string<\\DateTimeInterface> $class\n     */\n    #[DataProvider('getClasses')]\n    public function testNow(string $class)\n    {\n        date_default_timezone_set($timezone = 'Pacific/Honolulu');\n        $resolver = new DateTimeValueResolver();\n\n        $argument = new ArgumentMetadata('dummy', $class, false, false, null, false);\n        $request = self::requestWithAttributes(['dummy' => null]);\n\n        $results = $resolver->resolve($request, $argument);\n\n        $this->assertCount(1, $results);\n        $this->assertInstanceOf($class, $results[0]);\n        $this->assertSame($timezone, $results[0]->getTimezone()->getName(), 'Default timezone');\n        $this->assertEquals('0', $results[0]->diff(new \\DateTimeImmutable())->format('%s'));\n    }\n\n    /**\n     * @param class-string<\\DateTimeInterface> $class\n     */\n    #[DataProvider('getClasses')]\n    public function testNowWithClock(string $class)\n    {\n        date_default_timezone_set('Pacific/Honolulu');\n        $clock = new MockClock('2022-02-20 22:20:02');\n        $resolver = new DateTimeValueResolver($clock);\n\n        $argument = new ArgumentMetadata('dummy', $class, false, false, null, false);\n        $request = self::requestWithAttributes(['dummy' => null]);\n\n        $results = $resolver->resolve($request, $argument);\n\n        $this->assertCount(1, $results);\n        $this->assertInstanceOf($class, $results[0]);\n        $this->assertSame('UTC', $results[0]->getTimezone()->getName(), 'Default timezone');\n        $this->assertEquals($clock->now(), $results[0]);\n    }\n\n    /**\n     * @param class-string<\\DateTimeInterface> $class\n     */\n    #[DataProvider('getClasses')]\n    public function testPreviouslyConvertedAttribute(string $class)\n    {\n        $resolver = new DateTimeValueResolver();\n\n        $argument = new ArgumentMetadata('dummy', $class, false, false, null, true);\n        $request = self::requestWithAttributes(['dummy' => $datetime = new \\DateTimeImmutable()]);\n\n        $results = $resolver->resolve($request, $argument);\n\n        $this->assertCount(1, $results);\n        $this->assertEquals($datetime, $results[0], 'The value is the same, but the class can be modified.');\n        $this->assertInstanceOf($class, $results[0]);\n    }\n\n    public function testCustomClass()\n    {\n        date_default_timezone_set('UTC');\n        $resolver = new DateTimeValueResolver();\n\n        $argument = new ArgumentMetadata('dummy', FooDateTime::class, false, false, null);\n        $request = self::requestWithAttributes(['dummy' => '2016-09-08 00:00:00']);\n\n        $results = $resolver->resolve($request, $argument);\n\n        $this->assertCount(1, $results);\n        $this->assertInstanceOf(FooDateTime::class, $results[0]);\n        $this->assertEquals('2016-09-08 00:00:00+00:00', $results[0]->format('Y-m-d H:i:sP'));\n    }\n\n    #[DataProvider('getTimeZones')]\n    public function testDateTimeImmutable(string $timezone, bool $withClock)\n    {\n        date_default_timezone_set($withClock ? 'UTC' : $timezone);\n        $resolver = new DateTimeValueResolver($withClock ? new MockClock('now', $timezone) : null);\n\n        $argument = new ArgumentMetadata('dummy', \\DateTimeImmutable::class, false, false, null);\n        $request = self::requestWithAttributes(['dummy' => '2016-09-08 00:00:00 +05:00']);\n\n        $results = $resolver->resolve($request, $argument);\n\n        $this->assertCount(1, $results);\n        $this->assertInstanceOf(\\DateTimeImmutable::class, $results[0]);\n        $this->assertSame('+05:00', $results[0]->getTimezone()->getName(), 'Input timezone');\n        $this->assertEquals('2016-09-08 00:00:00', $results[0]->format('Y-m-d H:i:s'));\n    }\n\n    #[DataProvider('getTimeZones')]\n    public function testWithFormat(string $timezone, bool $withClock)\n    {\n        date_default_timezone_set($withClock ? 'UTC' : $timezone);\n        $resolver = new DateTimeValueResolver($withClock ? new MockClock('now', $timezone) : null);\n\n        $argument = new ArgumentMetadata('dummy', \\DateTimeInterface::class, false, false, null, false, [\n            MapDateTime::class => new MapDateTime('m-d-y H:i:s'),\n        ]);\n        $request = self::requestWithAttributes(['dummy' => '09-08-16 12:34:56']);\n\n        $results = $resolver->resolve($request, $argument);\n\n        $this->assertCount(1, $results);\n        $this->assertInstanceOf(\\DateTimeImmutable::class, $results[0]);\n        $this->assertSame($timezone, $results[0]->getTimezone()->getName(), 'Default timezone');\n        $this->assertEquals('2016-09-08 12:34:56', $results[0]->format('Y-m-d H:i:s'));\n    }\n\n    public static function provideInvalidDates()\n    {\n        return [\n            'invalid date' => [\n                new ArgumentMetadata('dummy', \\DateTimeImmutable::class, false, false, null),\n                self::requestWithAttributes(['dummy' => 'Invalid DateTime Format']),\n            ],\n            'invalid format' => [\n                new ArgumentMetadata('dummy', \\DateTimeImmutable::class, false, false, null, false, [new MapDateTime(format: 'd.m.Y')]),\n                self::requestWithAttributes(['dummy' => '2012-07-21']),\n            ],\n            'invalid ymd format' => [\n                new ArgumentMetadata('dummy', \\DateTimeImmutable::class, false, false, null, false, [new MapDateTime(format: 'Y-m-d')]),\n                self::requestWithAttributes(['dummy' => '2012-21-07']),\n            ],\n        ];\n    }\n\n    #[DataProvider('provideInvalidDates')]\n    public function test404Exception(ArgumentMetadata $argument, Request $request)\n    {\n        $resolver = new DateTimeValueResolver();\n\n        $this->expectException(NotFoundHttpException::class);\n        $this->expectExceptionMessage('Invalid date given for parameter \"dummy\".');\n\n        $resolver->resolve($request, $argument);\n    }\n\n    private static function requestWithAttributes(array $attributes): Request\n    {\n        $request = Request::create('/');\n\n        foreach ($attributes as $name => $value) {\n            $request->attributes->set($name, $value);\n        }\n\n        return $request;\n    }\n}\n\nclass FooDateTime extends \\DateTimeImmutable\n{\n}\n"
  },
  {
    "path": "Tests/Controller/ArgumentResolver/NotTaggedControllerValueResolverTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Controller\\ArgumentResolver;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\DependencyInjection\\Exception\\RuntimeException;\nuse Symfony\\Component\\DependencyInjection\\ServiceLocator;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\NotTaggedControllerValueResolver;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\n\nclass NotTaggedControllerValueResolverTest extends TestCase\n{\n    public function testDoNotSupportWhenControllerExists()\n    {\n        $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([\n            'App\\\\Controller\\\\Mine::method' => static fn () => new ServiceLocator([\n                'dummy' => static fn () => new \\stdClass(),\n            ]),\n        ]));\n        $argument = new ArgumentMetadata('dummy', \\stdClass::class, false, false, null);\n        $request = $this->requestWithAttributes(['_controller' => 'App\\\\Controller\\\\Mine::method']);\n        $this->assertSame([], $resolver->resolve($request, $argument));\n    }\n\n    public function testDoNotSupportEmptyController()\n    {\n        $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([]));\n        $argument = new ArgumentMetadata('dummy', \\stdClass::class, false, false, null);\n        $request = $this->requestWithAttributes(['_controller' => '']);\n        $this->assertSame([], $resolver->resolve($request, $argument));\n    }\n\n    public function testController()\n    {\n        $this->expectException(RuntimeException::class);\n        $this->expectExceptionMessage('Could not resolve argument $dummy of \"App\\Controller\\Mine::method()\", maybe you forgot to register the controller as a service or missed tagging it with the \"controller.service_arguments\"?');\n        $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([]));\n        $argument = new ArgumentMetadata('dummy', \\stdClass::class, false, false, null);\n        $request = $this->requestWithAttributes(['_controller' => 'App\\\\Controller\\\\Mine::method']);\n        $resolver->resolve($request, $argument);\n    }\n\n    public function testControllerWithATrailingBackSlash()\n    {\n        $this->expectException(RuntimeException::class);\n        $this->expectExceptionMessage('Could not resolve argument $dummy of \"App\\Controller\\Mine::method()\", maybe you forgot to register the controller as a service or missed tagging it with the \"controller.service_arguments\"?');\n        $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([]));\n        $argument = new ArgumentMetadata('dummy', \\stdClass::class, false, false, null);\n        $request = $this->requestWithAttributes(['_controller' => '\\\\App\\\\Controller\\\\Mine::method']);\n        $resolver->resolve($request, $argument);\n    }\n\n    public function testControllerWithMethodNameStartUppercase()\n    {\n        $this->expectException(RuntimeException::class);\n        $this->expectExceptionMessage('Could not resolve argument $dummy of \"App\\Controller\\Mine::method()\", maybe you forgot to register the controller as a service or missed tagging it with the \"controller.service_arguments\"?');\n        $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([]));\n        $argument = new ArgumentMetadata('dummy', \\stdClass::class, false, false, null);\n        $request = $this->requestWithAttributes(['_controller' => 'App\\\\Controller\\\\Mine::Method']);\n        $resolver->resolve($request, $argument);\n    }\n\n    public function testControllerNameIsAnArray()\n    {\n        $this->expectException(RuntimeException::class);\n        $this->expectExceptionMessage('Could not resolve argument $dummy of \"App\\Controller\\Mine::method()\", maybe you forgot to register the controller as a service or missed tagging it with the \"controller.service_arguments\"?');\n        $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([]));\n        $argument = new ArgumentMetadata('dummy', \\stdClass::class, false, false, null);\n        $request = $this->requestWithAttributes(['_controller' => ['App\\\\Controller\\\\Mine', 'method']]);\n        $resolver->resolve($request, $argument);\n    }\n\n    public function testInvokableController()\n    {\n        $this->expectException(RuntimeException::class);\n        $this->expectExceptionMessage('Could not resolve argument $dummy of \"App\\Controller\\Mine::__invoke()\", maybe you forgot to register the controller as a service or missed tagging it with the \"controller.service_arguments\"?');\n        $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([]));\n        $argument = new ArgumentMetadata('dummy', \\stdClass::class, false, false, null);\n        $request = $this->requestWithAttributes(['_controller' => 'App\\Controller\\Mine']);\n        $resolver->resolve($request, $argument);\n    }\n\n    private function requestWithAttributes(array $attributes)\n    {\n        $request = Request::create('/');\n        foreach ($attributes as $name => $value) {\n            $request->attributes->set($name, $value);\n        }\n\n        return $request;\n    }\n}\n"
  },
  {
    "path": "Tests/Controller/ArgumentResolver/QueryParameterValueResolverTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Controller\\ArgumentResolver;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Attribute\\MapQueryParameter;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\QueryParameterValueResolver;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Exception\\BadRequestHttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Suit;\nuse Symfony\\Component\\Uid\\Ulid;\n\nclass QueryParameterValueResolverTest extends TestCase\n{\n    private ValueResolverInterface $resolver;\n\n    protected function setUp(): void\n    {\n        $this->resolver = new QueryParameterValueResolver();\n    }\n\n    public function testSkipWhenNoAttribute()\n    {\n        $metadata = new ArgumentMetadata('firstName', 'string', false, true, false);\n\n        $this->assertSame([], $this->resolver->resolve(Request::create('/'), $metadata));\n    }\n\n    #[DataProvider('validDataProvider')]\n    public function testResolvingSuccessfully(Request $request, ArgumentMetadata $metadata, array $expected)\n    {\n        $this->assertEquals($expected, $this->resolver->resolve($request, $metadata));\n    }\n\n    #[DataProvider('invalidArgumentTypeProvider')]\n    public function testResolvingWithInvalidArgumentType(Request $request, ArgumentMetadata $metadata, string $exceptionMessage)\n    {\n        $this->expectException(\\LogicException::class);\n        $this->expectExceptionMessage($exceptionMessage);\n\n        $this->resolver->resolve($request, $metadata);\n    }\n\n    #[DataProvider('invalidOrMissingArgumentProvider')]\n    public function testResolvingWithInvalidOrMissingArgument(Request $request, ArgumentMetadata $metadata, HttpException $expectedException)\n    {\n        try {\n            $this->resolver->resolve($request, $metadata);\n\n            $this->fail(\\sprintf('Expected \"%s\" to be thrown.', HttpException::class));\n        } catch (HttpException $exception) {\n            $this->assertSame($expectedException->getMessage(), $exception->getMessage());\n            $this->assertSame($expectedException->getStatusCode(), $exception->getStatusCode());\n        }\n    }\n\n    /**\n     * @return iterable<string, array{\n     *   Request,\n     *   ArgumentMetadata,\n     *   array<mixed>,\n     * }>\n     */\n    public static function validDataProvider(): iterable\n    {\n        yield 'parameter found and array' => [\n            Request::create('/', 'GET', ['ids' => ['1', '2']]),\n            new ArgumentMetadata('ids', 'array', false, false, false, attributes: [new MapQueryParameter()]),\n            [['1', '2']],\n        ];\n\n        yield 'parameter found and array variadic' => [\n            Request::create('/', 'GET', ['ids' => [['1', '2'], ['2']]]),\n            new ArgumentMetadata('ids', 'array', true, false, false, attributes: [new MapQueryParameter()]),\n            [['1', '2'], ['2']],\n        ];\n\n        yield 'parameter found and string' => [\n            Request::create('/', 'GET', ['firstName' => 'John']),\n            new ArgumentMetadata('firstName', 'string', false, false, false, attributes: [new MapQueryParameter()]),\n            ['John'],\n        ];\n\n        yield 'parameter found and string variadic' => [\n            Request::create('/', 'GET', ['ids' => ['1', '2']]),\n            new ArgumentMetadata('ids', 'string', true, false, false, attributes: [new MapQueryParameter()]),\n            ['1', '2'],\n        ];\n\n        yield 'parameter found and string with regexp filter that matches' => [\n            Request::create('/', 'GET', ['firstName' => 'John']),\n            new ArgumentMetadata('firstName', 'string', false, false, false, attributes: [new MapQueryParameter(options: ['regexp' => '/John/'])]),\n            ['John'],\n        ];\n\n        yield 'parameter found and string with regexp filter that falls back to null on failure' => [\n            Request::create('/', 'GET', ['firstName' => 'Fabien']),\n            new ArgumentMetadata('firstName', 'string', false, false, false, attributes: [new MapQueryParameter(flags: \\FILTER_NULL_ON_FAILURE, options: ['regexp' => '/John/'])]),\n            [null],\n        ];\n\n        yield 'parameter found and string variadic with regexp filter that matches' => [\n            Request::create('/', 'GET', ['firstName' => ['John', 'John']]),\n            new ArgumentMetadata('firstName', 'string', true, false, false, attributes: [new MapQueryParameter(options: ['regexp' => '/John/'])]),\n            ['John', 'John'],\n        ];\n\n        yield 'parameter found and string variadic with regexp filter that falls back to null on failure' => [\n            Request::create('/', 'GET', ['firstName' => ['John', 'Fabien']]),\n            new ArgumentMetadata('firstName', 'string', true, false, false, attributes: [new MapQueryParameter(flags: \\FILTER_NULL_ON_FAILURE, options: ['regexp' => '/John/'])]),\n            ['John'],\n        ];\n\n        yield 'parameter found and integer' => [\n            Request::create('/', 'GET', ['age' => '123']),\n            new ArgumentMetadata('age', 'int', false, false, false, attributes: [new MapQueryParameter()]),\n            [123],\n        ];\n\n        yield 'parameter found and integer variadic' => [\n            Request::create('/', 'GET', ['age' => ['123', '222']]),\n            new ArgumentMetadata('age', 'int', true, false, false, attributes: [new MapQueryParameter()]),\n            [123, 222],\n        ];\n\n        yield 'parameter found and float' => [\n            Request::create('/', 'GET', ['price' => '10.99']),\n            new ArgumentMetadata('price', 'float', false, false, false, attributes: [new MapQueryParameter()]),\n            [10.99],\n        ];\n\n        yield 'parameter found and float variadic' => [\n            Request::create('/', 'GET', ['price' => ['10.99e2', '5.99']]),\n            new ArgumentMetadata('price', 'float', true, false, false, attributes: [new MapQueryParameter()]),\n            [1099.0, 5.99],\n        ];\n\n        yield 'parameter found and boolean yes' => [\n            Request::create('/', 'GET', ['isVerified' => 'yes']),\n            new ArgumentMetadata('isVerified', 'bool', false, false, false, attributes: [new MapQueryParameter()]),\n            [true],\n        ];\n\n        yield 'parameter found and boolean yes variadic' => [\n            Request::create('/', 'GET', ['isVerified' => ['yes', 'yes']]),\n            new ArgumentMetadata('isVerified', 'bool', true, false, false, attributes: [new MapQueryParameter()]),\n            [true, true],\n        ];\n\n        yield 'parameter found and boolean true' => [\n            Request::create('/', 'GET', ['isVerified' => 'true']),\n            new ArgumentMetadata('isVerified', 'bool', false, false, false, attributes: [new MapQueryParameter()]),\n            [true],\n        ];\n\n        yield 'parameter found and boolean 1' => [\n            Request::create('/', 'GET', ['isVerified' => '1']),\n            new ArgumentMetadata('isVerified', 'bool', false, false, false, attributes: [new MapQueryParameter()]),\n            [true],\n        ];\n\n        yield 'parameter found and boolean no' => [\n            Request::create('/', 'GET', ['isVerified' => 'no']),\n            new ArgumentMetadata('isVerified', 'bool', false, false, false, attributes: [new MapQueryParameter()]),\n            [false],\n        ];\n\n        yield 'parameter found and backing value' => [\n            Request::create('/', 'GET', ['suit' => 'H']),\n            new ArgumentMetadata('suit', Suit::class, false, false, false, attributes: [new MapQueryParameter()]),\n            [Suit::Hearts],\n        ];\n\n        yield 'parameter found and backing value variadic' => [\n            Request::create('/', 'GET', ['suits' => ['H', 'D']]),\n            new ArgumentMetadata('suits', Suit::class, true, false, false, attributes: [new MapQueryParameter()]),\n            [Suit::Hearts, Suit::Diamonds],\n        ];\n\n        yield 'parameter found and backing value not int nor string that fallbacks to null on failure' => [\n            Request::create('/', 'GET', ['suit' => 1]),\n            new ArgumentMetadata('suit', Suit::class, false, false, false, attributes: [new MapQueryParameter(filter: \\FILTER_VALIDATE_BOOL, flags: \\FILTER_NULL_ON_FAILURE)]),\n            [null],\n        ];\n\n        yield 'parameter found and value not valid backing value that falls back to null on failure' => [\n            Request::create('/', 'GET', ['suit' => 'B']),\n            new ArgumentMetadata('suit', Suit::class, false, false, false, attributes: [new MapQueryParameter(flags: \\FILTER_NULL_ON_FAILURE)]),\n            [null],\n        ];\n\n        yield 'parameter found and backing type variadic and at least one backing value not int nor string that fallbacks to null on failure' => [\n            Request::create('/', 'GET', ['suits' => ['1', 'D']]),\n            new ArgumentMetadata('suits', Suit::class, false, false, false, attributes: [new MapQueryParameter(flags: \\FILTER_NULL_ON_FAILURE)]),\n            [null],\n        ];\n\n        yield 'parameter found and backing type variadic and at least one value not valid backing value that falls back to null on failure' => [\n            Request::create('/', 'GET', ['suits' => ['B', 'D']]),\n            new ArgumentMetadata('suits', Suit::class, false, false, false, attributes: [new MapQueryParameter(flags: \\FILTER_NULL_ON_FAILURE)]),\n            [null],\n        ];\n\n        yield 'parameter not found but nullable' => [\n            Request::create('/', 'GET'),\n            new ArgumentMetadata('firstName', 'string', false, false, false, true, [new MapQueryParameter()]),\n            [],\n        ];\n\n        yield 'parameter not found but optional' => [\n            Request::create('/', 'GET'),\n            new ArgumentMetadata('firstName', 'string', false, true, false, attributes: [new MapQueryParameter()]),\n            [],\n        ];\n\n        yield 'parameter found and ULID' => [\n            Request::create('/', 'GET', ['groupId' => '01E439TP9XJZ9RPFH3T1PYBCR8']),\n            new ArgumentMetadata('groupId', Ulid::class, false, true, false, attributes: [new MapQueryParameter()]),\n            [Ulid::fromString('01E439TP9XJZ9RPFH3T1PYBCR8')],\n        ];\n    }\n\n    /**\n     * @return iterable<string, array{\n     *   Request,\n     *   ArgumentMetadata,\n     *   string,\n     * }>\n     */\n    public static function invalidArgumentTypeProvider(): iterable\n    {\n        yield 'unsupported type' => [\n            Request::create('/', 'GET', ['standardClass' => 'test']),\n            new ArgumentMetadata('standardClass', \\stdClass::class, false, false, false, attributes: [new MapQueryParameter()]),\n            '#[MapQueryParameter] cannot be used on controller argument \"$standardClass\" of type \"stdClass\"; one of array, string, int, float, bool, uid or \\BackedEnum should be used.',\n        ];\n\n        yield 'unsupported type variadic' => [\n            Request::create('/', 'GET', ['standardClass' => 'test']),\n            new ArgumentMetadata('standardClass', \\stdClass::class, true, false, false, attributes: [new MapQueryParameter()]),\n            '#[MapQueryParameter] cannot be used on controller argument \"...$standardClass\" of type \"stdClass\"; one of array, string, int, float, bool, uid or \\BackedEnum should be used.',\n        ];\n    }\n\n    /**\n     * @return iterable<string, array{\n     *   Request,\n     *   ArgumentMetadata,\n     *   HttpException,\n     * }>\n     */\n    public static function invalidOrMissingArgumentProvider(): iterable\n    {\n        yield 'parameter found and array variadic with parameter not array failure' => [\n            Request::create('/', 'GET', ['ids' => [['1', '2'], '1']]),\n            new ArgumentMetadata('ids', 'array', true, false, false, attributes: [new MapQueryParameter()]),\n            new NotFoundHttpException('Invalid query parameter \"ids\".'),\n        ];\n\n        yield 'parameter found and string with regexp filter that does not match' => [\n            Request::create('/', 'GET', ['firstName' => 'Fabien']),\n            new ArgumentMetadata('firstName', 'string', false, false, false, attributes: [new MapQueryParameter(filter: \\FILTER_VALIDATE_REGEXP, options: ['regexp' => '/John/'])]),\n            new NotFoundHttpException('Invalid query parameter \"firstName\".'),\n        ];\n\n        yield 'parameter found and string variadic with regexp filter that does not match' => [\n            Request::create('/', 'GET', ['firstName' => ['Fabien']]),\n            new ArgumentMetadata('firstName', 'string', true, false, false, attributes: [new MapQueryParameter(filter: \\FILTER_VALIDATE_REGEXP, options: ['regexp' => '/John/'])]),\n            new NotFoundHttpException('Invalid query parameter \"firstName\".'),\n        ];\n\n        yield 'parameter found and boolean invalid' => [\n            Request::create('/', 'GET', ['isVerified' => 'whatever']),\n            new ArgumentMetadata('isVerified', 'bool', false, false, false, attributes: [new MapQueryParameter()]),\n            new NotFoundHttpException('Invalid query parameter \"isVerified\".'),\n        ];\n\n        yield 'parameter found and backing value not int nor string' => [\n            Request::create('/', 'GET', ['suit' => 1]),\n            new ArgumentMetadata('suit', Suit::class, false, false, false, attributes: [new MapQueryParameter(filter: \\FILTER_VALIDATE_BOOL)]),\n            new NotFoundHttpException('Invalid query parameter \"suit\".'),\n        ];\n\n        yield 'parameter found and value not valid backing value' => [\n            Request::create('/', 'GET', ['suit' => 'B']),\n            new ArgumentMetadata('suit', Suit::class, false, false, false, attributes: [new MapQueryParameter()]),\n            new NotFoundHttpException('Invalid query parameter \"suit\".'),\n        ];\n\n        yield 'parameter found and backing type variadic and at least one backing value not int nor string' => [\n            Request::create('/', 'GET', ['suits' => [1, 'D']]),\n            new ArgumentMetadata('suits', Suit::class, false, false, false, attributes: [new MapQueryParameter(filter: \\FILTER_VALIDATE_BOOL)]),\n            new NotFoundHttpException('Invalid query parameter \"suits\".'),\n        ];\n\n        yield 'parameter found and backing type variadic and at least one value not valid backing value' => [\n            Request::create('/', 'GET', ['suits' => ['B', 'D']]),\n            new ArgumentMetadata('suits', Suit::class, false, false, false, attributes: [new MapQueryParameter()]),\n            new NotFoundHttpException('Invalid query parameter \"suits\".'),\n        ];\n\n        yield 'parameter not found' => [\n            Request::create('/', 'GET'),\n            new ArgumentMetadata('firstName', 'string', false, false, false, attributes: [new MapQueryParameter()]),\n            new NotFoundHttpException('Missing query parameter \"firstName\".'),\n        ];\n\n        yield 'parameter not found with custom validation failed status code' => [\n            Request::create('/', 'GET'),\n            new ArgumentMetadata('firstName', 'string', false, false, false, attributes: [new MapQueryParameter(validationFailedStatusCode: Response::HTTP_BAD_REQUEST)]),\n            new BadRequestHttpException('Missing query parameter \"firstName\".'),\n        ];\n    }\n}\n"
  },
  {
    "path": "Tests/Controller/ArgumentResolver/RequestAttributeValueResolverTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Controller\\ArgumentResolver;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\RequestAttributeValueResolver;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;\n\nclass RequestAttributeValueResolverTest extends TestCase\n{\n    public function testValidIntWithinRangeWorks()\n    {\n        $resolver = new RequestAttributeValueResolver();\n        $request = new Request();\n        $request->attributes->set('id', '123');\n        $metadata = new ArgumentMetadata('id', 'int', false, false, null);\n\n        $result = iterator_to_array($resolver->resolve($request, $metadata));\n\n        $this->assertSame([123], $result);\n    }\n\n    public function testInvalidStringBecomes404()\n    {\n        $resolver = new RequestAttributeValueResolver();\n        $request = new Request();\n        $request->attributes->set('id', 'abc');\n        $metadata = new ArgumentMetadata('id', 'int', false, false, null);\n\n        $this->expectException(NotFoundHttpException::class);\n        iterator_to_array($resolver->resolve($request, $metadata));\n    }\n\n    public function testOutOfRangeIntBecomes404()\n    {\n        $resolver = new RequestAttributeValueResolver();\n        $request = new Request();\n        // one more than PHP_INT_MAX on 64-bit (string input)\n        $request->attributes->set('id', '9223372036854775808');\n        $metadata = new ArgumentMetadata('id', 'int', false, false, null);\n\n        $this->expectException(NotFoundHttpException::class);\n        iterator_to_array($resolver->resolve($request, $metadata));\n    }\n\n    public function testNullableIntAllowsNull()\n    {\n        $resolver = new RequestAttributeValueResolver();\n        $request = new Request();\n        $request->attributes->set('id', null);\n        $metadata = new ArgumentMetadata('id', 'int', false, true, null);\n\n        $result = iterator_to_array($resolver->resolve($request, $metadata));\n\n        $this->assertSame([null], $result);\n    }\n}\n"
  },
  {
    "path": "Tests/Controller/ArgumentResolver/RequestHeaderValueResolverTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Controller\\ArgumentResolver;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\AcceptHeader;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Attribute\\MapRequestHeader;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\RequestHeaderValueResolver;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\n\nclass RequestHeaderValueResolverTest extends TestCase\n{\n    public static function provideHeaderValueWithStringType(): iterable\n    {\n        yield 'with accept' => ['accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'];\n        yield 'with accept-language' => ['accept-language', 'en-us,en;q=0.5'];\n        yield 'with host' => ['host', 'localhost'];\n        yield 'with user-agent' => ['user-agent', 'Symfony'];\n    }\n\n    public static function provideHeaderValueWithArrayType(): iterable\n    {\n        yield 'with accept' => [\n            'accept',\n            'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',\n            [\n                [\n                    'text/html',\n                    'application/xhtml+xml',\n                    'application/xml',\n                    '*/*',\n                ],\n            ],\n        ];\n        yield 'with accept-language' => [\n            'accept-language',\n            'en-us,en;q=0.5',\n            [\n                [\n                    'en_US',\n                    'en',\n                ],\n            ],\n        ];\n        yield 'with host' => [\n            'host',\n            'localhost',\n            [\n                ['localhost'],\n            ],\n        ];\n        yield 'with user-agent' => [\n            'user-agent',\n            'Symfony',\n            [\n                ['Symfony'],\n            ],\n        ];\n    }\n\n    public static function provideHeaderValueWithAcceptHeaderType(): iterable\n    {\n        yield 'with accept' => [\n            'accept',\n            'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',\n            [AcceptHeader::fromString('text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8')],\n        ];\n        yield 'with accept-language' => [\n            'accept-language',\n            'en-us,en;q=0.5',\n            [AcceptHeader::fromString('en-us,en;q=0.5')],\n        ];\n        yield 'with host' => [\n            'host',\n            'localhost',\n            [AcceptHeader::fromString('localhost')],\n        ];\n        yield 'with user-agent' => [\n            'user-agent',\n            'Symfony',\n            [AcceptHeader::fromString('Symfony')],\n        ];\n    }\n\n    public static function provideHeaderValueWithDefaultAndNull(): iterable\n    {\n        yield 'with hasDefaultValue' => [true, 'foo', false, 'foo'];\n        yield 'with no isNullable' => [false, null, true, null];\n    }\n\n    public function testWrongType()\n    {\n        $this->expectException(\\LogicException::class);\n\n        $metadata = new ArgumentMetadata('accept', 'int', false, false, null, false, [\n            new MapRequestHeader(),\n        ]);\n\n        $request = Request::create('/');\n\n        $resolver = new RequestHeaderValueResolver();\n        $resolver->resolve($request, $metadata);\n    }\n\n    #[DataProvider('provideHeaderValueWithStringType')]\n    public function testWithStringType(string $parameter, string $value)\n    {\n        $resolver = new RequestHeaderValueResolver();\n\n        $metadata = new ArgumentMetadata('variableName', 'string', false, false, null, false, [\n            new MapRequestHeader($parameter),\n        ]);\n\n        $request = Request::create('/');\n        $request->headers->set($parameter, $value);\n\n        $arguments = $resolver->resolve($request, $metadata);\n\n        self::assertEquals([$value], $arguments);\n    }\n\n    #[DataProvider('provideHeaderValueWithArrayType')]\n    public function testWithArrayType(string $parameter, string $value, array $expected)\n    {\n        $resolver = new RequestHeaderValueResolver();\n\n        $metadata = new ArgumentMetadata('variableName', 'array', false, false, null, false, [\n            new MapRequestHeader($parameter),\n        ]);\n\n        $request = Request::create('/');\n        $request->headers->set($parameter, $value);\n\n        $arguments = $resolver->resolve($request, $metadata);\n\n        self::assertEquals($expected, $arguments);\n    }\n\n    #[DataProvider('provideHeaderValueWithAcceptHeaderType')]\n    public function testWithAcceptHeaderType(string $parameter, string $value, array $expected)\n    {\n        $resolver = new RequestHeaderValueResolver();\n\n        $metadata = new ArgumentMetadata('variableName', AcceptHeader::class, false, false, null, false, [\n            new MapRequestHeader($parameter),\n        ]);\n\n        $request = Request::create('/');\n        $request->headers->set($parameter, $value);\n\n        $arguments = $resolver->resolve($request, $metadata);\n\n        self::assertEquals($expected, $arguments);\n    }\n\n    #[DataProvider('provideHeaderValueWithDefaultAndNull')]\n    public function testWithDefaultValueAndNull(bool $hasDefaultValue, ?string $defaultValue, bool $isNullable, ?string $expected)\n    {\n        $metadata = new ArgumentMetadata('wrong-header', 'string', false, $hasDefaultValue, $defaultValue, $isNullable, [\n            new MapRequestHeader(),\n        ]);\n\n        $request = Request::create('/');\n\n        $resolver = new RequestHeaderValueResolver();\n        $arguments = $resolver->resolve($request, $metadata);\n\n        self::assertEquals([$expected], $arguments);\n    }\n\n    public function testCamelCaseArgumentNameMapsToKebabCaseHeader()\n    {\n        $resolver = new RequestHeaderValueResolver();\n\n        $metadata = new ArgumentMetadata('acceptEncoding', 'string', false, false, null, false, [\n            new MapRequestHeader(),\n        ]);\n\n        $request = Request::create('/');\n        $request->headers->set('accept-encoding', 'gzip, deflate');\n\n        $arguments = $resolver->resolve($request, $metadata);\n\n        self::assertSame(['gzip, deflate'], $arguments);\n    }\n\n    public function testWithNoDefaultAndNotNullable()\n    {\n        $this->expectException(HttpException::class);\n        $this->expectExceptionMessage('Missing header \"variable-name\".');\n\n        $metadata = new ArgumentMetadata('variableName', 'string', false, false, null, false, [\n            new MapRequestHeader(),\n        ]);\n\n        $resolver = new RequestHeaderValueResolver();\n        $resolver->resolve(Request::create('/'), $metadata);\n    }\n\n    public function testWithNoDefaultAndNotNullableArray()\n    {\n        $metadata = new ArgumentMetadata('variableName', 'array', false, false, null, false, [\n            new MapRequestHeader(),\n        ]);\n\n        $resolver = new RequestHeaderValueResolver();\n        $arguments = $resolver->resolve(Request::create('/'), $metadata);\n\n        self::assertEquals([[]], $arguments);\n    }\n}\n"
  },
  {
    "path": "Tests/Controller/ArgumentResolver/RequestPayloadValueResolverTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Controller\\ArgumentResolver;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\Attributes\\TestWith;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\ExpressionLanguage\\Expression;\nuse Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage;\nuse Symfony\\Component\\HttpFoundation\\File\\UploadedFile;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Attribute\\MapQueryString;\nuse Symfony\\Component\\HttpKernel\\Attribute\\MapRequestPayload;\nuse Symfony\\Component\\HttpKernel\\Attribute\\ValueResolver;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\RequestPayloadValueResolver;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerEvent;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\NearMissValueResolverException;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller\\BasicTypesController;\nuse Symfony\\Component\\PropertyInfo\\Extractor\\ReflectionExtractor;\nuse Symfony\\Component\\Serializer\\Encoder\\JsonEncoder;\nuse Symfony\\Component\\Serializer\\Encoder\\XmlEncoder;\nuse Symfony\\Component\\Serializer\\Exception\\NotNormalizableValueException;\nuse Symfony\\Component\\Serializer\\Exception\\PartialDenormalizationException;\nuse Symfony\\Component\\Serializer\\Normalizer\\ArrayDenormalizer;\nuse Symfony\\Component\\Serializer\\Normalizer\\BackedEnumNormalizer;\nuse Symfony\\Component\\Serializer\\Normalizer\\DenormalizerInterface;\nuse Symfony\\Component\\Serializer\\Normalizer\\ObjectNormalizer;\nuse Symfony\\Component\\Serializer\\Serializer;\nuse Symfony\\Component\\Serializer\\SerializerInterface;\nuse Symfony\\Component\\Validator\\Constraints as Assert;\nuse Symfony\\Component\\Validator\\ConstraintViolation;\nuse Symfony\\Component\\Validator\\ConstraintViolationList;\nuse Symfony\\Component\\Validator\\Exception\\ValidationFailedException;\nuse Symfony\\Component\\Validator\\Validator\\ValidatorInterface;\nuse Symfony\\Component\\Validator\\ValidatorBuilder;\n\nclass RequestPayloadValueResolverTest extends TestCase\n{\n    private const string FIXTURES_BASE_PATH = __DIR__.'/../../Fixtures/Controller/ArgumentResolver/UploadedFile';\n\n    public function testNotTypedArgument()\n    {\n        $resolver = new RequestPayloadValueResolver(\n            new Serializer(),\n            (new ValidatorBuilder())->getValidator(),\n        );\n\n        $argument = new ArgumentMetadata('notTyped', null, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = Request::create('/', 'POST', server: ['HTTP_CONTENT_TYPE' => 'application/json']);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $this->expectException(\\LogicException::class);\n        $this->expectExceptionMessage('Could not resolve the \"$notTyped\" controller argument: argument should be typed.');\n\n        $resolver->onKernelControllerArguments($event);\n    }\n\n    public function testDefaultValueArgument()\n    {\n        $payload = new RequestPayload(50);\n\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->never())\n           ->method('validate');\n\n        $resolver = new RequestPayloadValueResolver(new Serializer(), $validator);\n\n        $argument = new ArgumentMetadata('valid', RequestPayload::class, false, true, $payload, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = Request::create('/', 'POST', server: ['CONTENT_TYPE' => 'application/json']);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static fn () => null, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertEquals([$payload], $event->getArguments());\n    }\n\n    public function testQueryDefaultValueArgument()\n    {\n        $payload = new RequestPayload(50);\n\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->never())\n            ->method('validate');\n\n        $resolver = new RequestPayloadValueResolver(new Serializer(), $validator);\n\n        $argument = new ArgumentMetadata('valid', RequestPayload::class, false, true, $payload, false, [\n            MapQueryString::class => new MapQueryString(),\n        ]);\n        $request = Request::create('/', 'GET');\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static fn () => null, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertEquals([$payload], $event->getArguments());\n    }\n\n    public function testNullableValueArgument()\n    {\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->never())\n            ->method('validate');\n\n        $resolver = new RequestPayloadValueResolver(new Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]), $validator);\n\n        $argument = new ArgumentMetadata('valid', RequestPayload::class, false, false, null, true, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = Request::create('/', 'POST', server: ['CONTENT_TYPE' => 'application/json']);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static fn () => null, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertSame([null], $event->getArguments());\n    }\n\n    public function testQueryNullableValueArgument()\n    {\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->never())\n            ->method('validate');\n\n        $resolver = new RequestPayloadValueResolver(new Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]), $validator);\n\n        $argument = new ArgumentMetadata('valid', QueryPayload::class, false, false, null, true, [\n            MapQueryString::class => new MapQueryString(),\n        ]);\n        $request = Request::create('/', 'GET');\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static fn () => null, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertSame([null], $event->getArguments());\n    }\n\n    public function testMapQueryStringEmpty()\n    {\n        $payload = new RequestPayload(50);\n        $denormalizer = new RequestPayloadDenormalizer($payload);\n        $serializer = new Serializer([$denormalizer]);\n        $resolver = new RequestPayloadValueResolver($serializer);\n        $argument = new ArgumentMetadata('valid', RequestPayload::class, false, false, null, false, [\n            MapQueryString::class => new MapQueryString(mapWhenEmpty: true),\n        ]);\n        $request = Request::create('/', 'GET');\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static fn () => null, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertSame([$payload], $event->getArguments());\n    }\n\n    public function testMapRequestPayloadEmpty()\n    {\n        $payload = new RequestPayload(50);\n        $denormalizer = new RequestPayloadDenormalizer($payload);\n        $serializer = new Serializer([$denormalizer]);\n        $resolver = new RequestPayloadValueResolver($serializer);\n        $argument = new ArgumentMetadata('valid', RequestPayload::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(mapWhenEmpty: true),\n        ]);\n        $request = Request::create('/', 'POST');\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static fn () => null, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertSame([$payload], $event->getArguments());\n    }\n\n    public function testNullPayloadAndNotDefaultOrNullableArgument()\n    {\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->never())\n            ->method('validate');\n\n        $resolver = new RequestPayloadValueResolver(new Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]), $validator);\n\n        $argument = new ArgumentMetadata('valid', RequestPayload::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = Request::create('/', 'POST', server: ['CONTENT_TYPE' => 'application/json']);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static fn () => null, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        try {\n            $resolver->onKernelControllerArguments($event);\n            $this->fail(\\sprintf('Expected \"%s\" to be thrown.', HttpException::class));\n        } catch (HttpException $e) {\n            $this->assertSame(400, $e->getStatusCode());\n        }\n    }\n\n    public function testRequestPayloadWithoutContentTypeOnNullableArgumentReturnsNull()\n    {\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->never())\n            ->method('validate');\n\n        $resolver = new RequestPayloadValueResolver(new Serializer(), $validator);\n\n        $argument = new ArgumentMetadata('valid', RequestPayload::class, false, false, null, true, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = Request::create('/', 'POST');\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static fn () => null, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertSame([null], $event->getArguments());\n    }\n\n    public function testQueryNullPayloadAndNotDefaultOrNullableArgument()\n    {\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->never())\n            ->method('validate');\n\n        $resolver = new RequestPayloadValueResolver(new Serializer([new ObjectNormalizer()]), $validator);\n\n        $argument = new ArgumentMetadata('valid', QueryPayload::class, false, false, null, false, [\n            MapQueryString::class => new MapQueryString(),\n        ]);\n        $request = Request::create('/', 'GET');\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static fn () => null, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        try {\n            $resolver->onKernelControllerArguments($event);\n            $this->fail(\\sprintf('Expected \"%s\" to be thrown.', HttpException::class));\n        } catch (HttpException $e) {\n            $this->assertSame(404, $e->getStatusCode());\n        }\n    }\n\n    public function testWithoutValidatorAndCouldNotDenormalize()\n    {\n        $content = '{\"price\": 50, \"title\": [\"not a string\"]}';\n        $serializer = new Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]);\n\n        $resolver = new RequestPayloadValueResolver($serializer);\n\n        $argument = new ArgumentMetadata('invalid', RequestPayload::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = Request::create('/', 'POST', server: ['CONTENT_TYPE' => 'application/json'], content: $content);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        try {\n            $resolver->onKernelControllerArguments($event);\n            $this->fail(\\sprintf('Expected \"%s\" to be thrown.', HttpException::class));\n        } catch (HttpException $e) {\n            $this->assertInstanceOf(PartialDenormalizationException::class, $e->getPrevious());\n        }\n    }\n\n    public function testValidationNotPassed()\n    {\n        $content = '{\"price\": 50.0, \"title\": [\"not a string\"]}';\n        $serializer = new Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]);\n\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->never())\n            ->method('validate');\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('invalid', RequestPayload::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = Request::create('/', 'POST', server: ['CONTENT_TYPE' => 'application/json'], content: $content);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        try {\n            $resolver->onKernelControllerArguments($event);\n            $this->fail(\\sprintf('Expected \"%s\" to be thrown.', HttpException::class));\n        } catch (HttpException $e) {\n            $validationFailedException = $e->getPrevious();\n            $this->assertSame(422, $e->getStatusCode());\n            $this->assertInstanceOf(ValidationFailedException::class, $validationFailedException);\n            $this->assertSame('This value should be of type string.', $validationFailedException->getViolations()[0]->getMessage());\n        }\n    }\n\n    public function testValidationFailedOnInvalidBackedEnum()\n    {\n        $content = '{\"method\": \"INVALID\"}';\n        $serializer = new Serializer([new BackedEnumNormalizer(), new ObjectNormalizer()], ['json' => new JsonEncoder()]);\n\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->never())\n            ->method('validate');\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('invalid', RequestPayloadWithBackedEnum::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = Request::create('/', 'POST', server: ['CONTENT_TYPE' => 'application/json'], content: $content);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        try {\n            $resolver->onKernelControllerArguments($event);\n            $this->fail(\\sprintf('Expected \"%s\" to be thrown.', HttpException::class));\n        } catch (HttpException $e) {\n            $validationFailedException = $e->getPrevious();\n            $this->assertSame(422, $e->getStatusCode());\n            $this->assertInstanceOf(ValidationFailedException::class, $validationFailedException);\n            $this->assertContains($validationFailedException->getViolations()[0]->getMessage(), [\n                'This value should be of type int|string.',\n                'The data must belong to a backed enumeration of type Symfony\\\\Component\\\\HttpKernel\\\\Tests\\\\Controller\\\\ArgumentResolver\\\\RequestMethod',\n            ]);\n        }\n    }\n\n    public function testValidationNotPerformedWhenPartialDenormalizationReturnsViolation()\n    {\n        $content = '{\"password\": \"abc\"}';\n        $serializer = new Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]);\n\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->never())\n            ->method('validate');\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('invalid', User::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = Request::create('/', 'POST', server: ['CONTENT_TYPE' => 'application/json'], content: $content);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        try {\n            $resolver->onKernelControllerArguments($event);\n            $this->fail(\\sprintf('Expected \"%s\" to be thrown.', HttpException::class));\n        } catch (HttpException $e) {\n            $validationFailedException = $e->getPrevious();\n            $this->assertInstanceOf(ValidationFailedException::class, $validationFailedException);\n            $this->assertSame('This value should be of type string.', $validationFailedException->getViolations()[0]->getMessage());\n        }\n    }\n\n    public function testUnsupportedMedia()\n    {\n        $serializer = new Serializer();\n\n        $resolver = new RequestPayloadValueResolver($serializer);\n\n        $argument = new ArgumentMetadata('invalid', \\stdClass::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = Request::create('/', 'POST', server: ['CONTENT_TYPE' => 'foo/bar'], content: 'foo-bar');\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        try {\n            $resolver->onKernelControllerArguments($event);\n            $this->fail(\\sprintf('Expected \"%s\" to be thrown.', HttpException::class));\n        } catch (HttpException $e) {\n            $this->assertSame(415, $e->getStatusCode());\n        }\n    }\n\n    public function testRequestContentValidationPassed()\n    {\n        $content = '{\"price\": 50}';\n        $payload = new RequestPayload(50);\n        $serializer = new Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]);\n\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->once())\n            ->method('validate')\n            ->willReturn(new ConstraintViolationList());\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('valid', RequestPayload::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = Request::create('/', 'POST', server: ['CONTENT_TYPE' => 'application/json'], content: $content);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertEquals([$payload], $event->getArguments());\n    }\n\n    #[TestWith([null])]\n    #[TestWith([[]])]\n    public function testRequestContentWithUntypedErrors(?array $types)\n    {\n        $this->expectException(HttpException::class);\n        $this->expectExceptionMessage('This value was of an unexpected type.');\n        $serializer = $this->createStub(SerializerDenormalizer::class);\n\n        if (null === $types) {\n            $exception = new NotNormalizableValueException('Error with no types');\n        } else {\n            $exception = NotNormalizableValueException::createForUnexpectedDataType('Error with no types', '', []);\n        }\n        $serializer->method('deserialize')->willThrowException(new PartialDenormalizationException([], [$exception]));\n\n        $resolver = new RequestPayloadValueResolver($serializer, (new ValidatorBuilder())->getValidator());\n        $request = Request::create('/', 'POST', server: ['CONTENT_TYPE' => 'application/json'], content: '{\"price\": 50}');\n\n        $arguments = $resolver->resolve($request, new ArgumentMetadata('valid', RequestPayload::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]));\n        $event = new ControllerArgumentsEvent($this->createStub(HttpKernelInterface::class), static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n    }\n\n    public function testQueryStringValidationPassed()\n    {\n        $payload = new RequestPayload(50);\n        $query = ['price' => '50'];\n\n        $serializer = new Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]);\n\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->once())\n            ->method('validate')\n            ->willReturn(new ConstraintViolationList());\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('valid', RequestPayload::class, false, false, null, false, [\n            MapQueryString::class => new MapQueryString(),\n        ]);\n        $request = Request::create('/', 'GET', $query);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertEquals([$payload], $event->getArguments());\n    }\n\n    public function testQueryStringParameterTypeMismatch()\n    {\n        $query = ['price' => 'not a float'];\n\n        $normalizer = new ObjectNormalizer(null, null, null, new ReflectionExtractor());\n        $serializer = new Serializer([$normalizer], ['json' => new JsonEncoder()]);\n\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->never())->method('validate');\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('invalid', RequestPayload::class, false, false, null, false, [\n            MapQueryString::class => new MapQueryString(),\n        ]);\n\n        $request = Request::create('/', 'GET', $query);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        try {\n            $resolver->onKernelControllerArguments($event);\n            $this->fail(\\sprintf('Expected \"%s\" to be thrown.', HttpException::class));\n        } catch (HttpException $e) {\n            $validationFailedException = $e->getPrevious();\n            $this->assertInstanceOf(ValidationFailedException::class, $validationFailedException);\n            $this->assertSame('This value should be of type float.', $validationFailedException->getViolations()[0]->getMessage());\n        }\n    }\n\n    public function testRequestInputValidationPassed()\n    {\n        $input = ['price' => '50'];\n        $payload = new RequestPayload(50);\n\n        $serializer = new Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]);\n\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->once())\n            ->method('validate')\n            ->willReturn(new ConstraintViolationList());\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('valid', RequestPayload::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = Request::create('/', 'POST', $input);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertEquals([$payload], $event->getArguments());\n    }\n\n    public function testRequestArrayDenormalization()\n    {\n        $input = [\n            ['price' => '50'],\n            ['price' => '23'],\n        ];\n        $payload = [\n            new RequestPayload(50),\n            new RequestPayload(23),\n        ];\n\n        $serializer = new Serializer([new ArrayDenormalizer(), new ObjectNormalizer()], ['json' => new JsonEncoder()]);\n\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->once())\n            ->method('validate')\n            ->willReturn(new ConstraintViolationList());\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('prices', 'array', false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(type: RequestPayload::class),\n        ]);\n        $request = Request::create('/', 'POST', $input);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertEquals([$payload], $event->getArguments());\n    }\n\n    public function testRequestInputTypeMismatch()\n    {\n        $input = ['price' => 'not a float'];\n\n        $normalizer = new ObjectNormalizer(null, null, null, new ReflectionExtractor());\n        $serializer = new Serializer([$normalizer], ['json' => new JsonEncoder()]);\n\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->never())->method('validate');\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('invalid', RequestPayload::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n\n        $request = Request::create('/', 'POST', $input);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        try {\n            $resolver->onKernelControllerArguments($event);\n            $this->fail(\\sprintf('Expected \"%s\" to be thrown.', HttpException::class));\n        } catch (HttpException $e) {\n            $validationFailedException = $e->getPrevious();\n            $this->assertInstanceOf(ValidationFailedException::class, $validationFailedException);\n            $this->assertSame('This value should be of type float.', $validationFailedException->getViolations()[0]->getMessage());\n        }\n    }\n\n    public function testItThrowsOnMissingAttributeType()\n    {\n        $serializer = new Serializer();\n        $validator = (new ValidatorBuilder())->getValidator();\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('prices', 'array', false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = Request::create('/', 'POST');\n        $request->attributes->set('_controller', 'App\\Controller\\SomeController::someMethod');\n\n        $this->expectException(NearMissValueResolverException::class);\n        $this->expectExceptionMessage('Please set the $type argument of the #[Symfony\\Component\\HttpKernel\\Attribute\\MapRequestPayload] attribute to the type of the objects in the expected array.');\n        $resolver->resolve($request, $argument);\n    }\n\n    public function testItThrowsOnInvalidAttributeTypeUsage()\n    {\n        $serializer = new Serializer();\n        $validator = (new ValidatorBuilder())->getValidator();\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('prices', null, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(type: RequestPayload::class),\n        ]);\n        $request = Request::create('/', 'POST');\n        $request->attributes->set('_controller', 'App\\Controller\\SomeController::someMethod');\n\n        $this->expectException(NearMissValueResolverException::class);\n        $this->expectExceptionMessage('Please set its type to \"array\" when using argument $type of #[Symfony\\Component\\HttpKernel\\Attribute\\MapRequestPayload].');\n        $resolver->resolve($request, $argument);\n    }\n\n    public function testItThrowsOnVariadicArgument()\n    {\n        $serializer = new Serializer();\n        $validator = (new ValidatorBuilder())->getValidator();\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('variadic', RequestPayload::class, true, false, null, false, [\n            MapQueryString::class => new MapQueryString(),\n        ]);\n        $request = Request::create('/', 'POST');\n\n        $this->expectException(\\LogicException::class);\n        $this->expectExceptionMessage('Mapping variadic argument \"$variadic\" is not supported.');\n        $resolver->resolve($request, $argument);\n    }\n\n    #[DataProvider('provideMatchedFormatContext')]\n    public function testAcceptFormatPassed(mixed $acceptFormat, string $contentType, string $content)\n    {\n        $encoders = ['json' => new JsonEncoder(), 'xml' => new XmlEncoder()];\n        $serializer = new Serializer([new ObjectNormalizer()], $encoders);\n        $validator = (new ValidatorBuilder())->getValidator();\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $request = Request::create('/', 'POST', server: ['CONTENT_TYPE' => $contentType], content: $content);\n\n        $argument = new ArgumentMetadata('valid', RequestPayload::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(acceptFormat: $acceptFormat),\n        ]);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertEquals([new RequestPayload(50)], $event->getArguments());\n    }\n\n    public static function provideMatchedFormatContext(): iterable\n    {\n        yield 'configure with json as string, sends json' => [\n            'acceptFormat' => 'json',\n            'contentType' => 'application/json',\n            'content' => '{\"price\": 50}',\n        ];\n\n        yield 'configure with json as array, sends json' => [\n            'acceptFormat' => ['json'],\n            'contentType' => 'application/json',\n            'content' => '{\"price\": 50}',\n        ];\n\n        yield 'configure with xml as string, sends xml' => [\n            'acceptFormat' => 'xml',\n            'contentType' => 'application/xml',\n            'content' => '<?xml version=\"1.0\"?><request><price>50</price></request>',\n        ];\n\n        yield 'configure with xml as array, sends xml' => [\n            'acceptFormat' => ['xml'],\n            'contentType' => 'application/xml',\n            'content' => '<?xml version=\"1.0\"?><request><price>50</price></request>',\n        ];\n\n        yield 'configure with json or xml, sends json' => [\n            'acceptFormat' => ['json', 'xml'],\n            'contentType' => 'application/json',\n            'content' => '{\"price\": 50}',\n        ];\n\n        yield 'configure with json or xml, sends xml' => [\n            'acceptFormat' => ['json', 'xml'],\n            'contentType' => 'application/xml',\n            'content' => '<?xml version=\"1.0\"?><request><price>50</price></request>',\n        ];\n    }\n\n    #[DataProvider('provideMismatchedFormatContext')]\n    public function testAcceptFormatNotPassed(mixed $acceptFormat, string $contentType, string $content, string $expectedExceptionMessage)\n    {\n        $serializer = new Serializer([new ObjectNormalizer()]);\n        $validator = (new ValidatorBuilder())->getValidator();\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $request = Request::create('/', 'POST', server: ['CONTENT_TYPE' => $contentType], content: $content);\n\n        $argument = new ArgumentMetadata('valid', RequestPayload::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(acceptFormat: $acceptFormat),\n        ]);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        try {\n            $resolver->onKernelControllerArguments($event);\n            $this->fail(\\sprintf('Expected \"%s\" to be thrown.', HttpException::class));\n        } catch (HttpException $e) {\n            $this->assertSame(415, $e->getStatusCode());\n            $this->assertSame($expectedExceptionMessage, $e->getMessage());\n        }\n    }\n\n    public static function provideMismatchedFormatContext(): iterable\n    {\n        yield 'configure with json as string, sends xml' => [\n            'acceptFormat' => 'json',\n            'contentType' => 'application/xml',\n            'content' => '<?xml version=\"1.0\"?><request><price>50</price></request>',\n            'expectedExceptionMessage' => 'Unsupported format, expects \"json\", but \"xml\" given.',\n        ];\n\n        yield 'configure with json as array, sends xml' => [\n            'acceptFormat' => ['json'],\n            'contentType' => 'application/xml',\n            'content' => '<?xml version=\"1.0\"?><request><price>50</price></request>',\n            'expectedExceptionMessage' => 'Unsupported format, expects \"json\", but \"xml\" given.',\n        ];\n\n        yield 'configure with xml as string, sends json' => [\n            'acceptFormat' => 'xml',\n            'contentType' => 'application/json',\n            'content' => '{\"price\": 50}',\n            'expectedExceptionMessage' => 'Unsupported format, expects \"xml\", but \"json\" given.',\n        ];\n\n        yield 'configure with xml as array, sends json' => [\n            'acceptFormat' => ['xml'],\n            'contentType' => 'application/json',\n            'content' => '{\"price\": 50}',\n            'expectedExceptionMessage' => 'Unsupported format, expects \"xml\", but \"json\" given.',\n        ];\n\n        yield 'configure with json or xml, sends jsonld' => [\n            'acceptFormat' => ['json', 'xml'],\n            'contentType' => 'application/ld+json',\n            'content' => '{\"@context\": \"https://schema.org\", \"@type\": \"FakeType\", \"price\": 50}',\n            'expectedExceptionMessage' => 'Unsupported format, expects \"json\", \"xml\", but \"jsonld\" given.',\n        ];\n    }\n\n    #[DataProvider('provideValidationGroupsOnManyTypes')]\n    public function testValidationGroupsPassed(string $method, ValueResolver $attribute)\n    {\n        $input = ['price' => '50', 'title' => 'A long title, so the validation passes'];\n\n        $payload = new RequestPayload(50);\n        $payload->title = 'A long title, so the validation passes';\n\n        $serializer = new Serializer([new ObjectNormalizer()]);\n        $validator = (new ValidatorBuilder())->enableAttributeMapping()->getValidator();\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $request = Request::create('/', $method, $input);\n\n        $argument = new ArgumentMetadata('valid', RequestPayload::class, false, false, null, false, [\n            $attribute::class => $attribute,\n        ]);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertEquals([$payload], $event->getArguments());\n    }\n\n    #[DataProvider('provideValidationGroupsOnManyTypes')]\n    public function testValidationGroupsNotPassed(string $method, ValueResolver $attribute)\n    {\n        $input = ['price' => '50', 'title' => 'Too short'];\n\n        $serializer = new Serializer([new ObjectNormalizer()]);\n        $validator = (new ValidatorBuilder())->enableAttributeMapping()->getValidator();\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('valid', RequestPayload::class, false, false, null, false, [\n            $attribute::class => $attribute,\n        ]);\n        $request = Request::create('/', $method, $input);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        try {\n            $resolver->onKernelControllerArguments($event);\n            $this->fail(\\sprintf('Expected \"%s\" to be thrown.', HttpException::class));\n        } catch (HttpException $e) {\n            $validationFailedException = $e->getPrevious();\n            $this->assertInstanceOf(ValidationFailedException::class, $validationFailedException);\n            $this->assertSame('title', $validationFailedException->getViolations()[0]->getPropertyPath());\n            $this->assertSame('This value is too short. It should have 10 characters or more.', $validationFailedException->getViolations()[0]->getMessage());\n        }\n    }\n\n    public static function provideValidationGroupsOnManyTypes(): iterable\n    {\n        yield 'request payload with validation group as string' => [\n            'POST',\n            new MapRequestPayload(validationGroups: 'strict'),\n        ];\n\n        yield 'request payload with validation group as array' => [\n            'POST',\n            new MapRequestPayload(validationGroups: ['strict']),\n        ];\n\n        yield 'request payload with validation group as GroupSequence' => [\n            'POST',\n            new MapRequestPayload(validationGroups: new Assert\\GroupSequence(['strict'])),\n        ];\n\n        yield 'query with validation group as string' => [\n            'GET',\n            new MapQueryString(validationGroups: 'strict'),\n        ];\n\n        yield 'query with validation group as array' => [\n            'GET',\n            new MapQueryString(validationGroups: ['strict']),\n        ];\n\n        yield 'query with validation group as GroupSequence' => [\n            'GET',\n            new MapQueryString(validationGroups: new Assert\\GroupSequence(['strict'])),\n        ];\n    }\n\n    public function testQueryValidationErrorCustomStatusCode()\n    {\n        $serializer = new Serializer([new ObjectNormalizer()], []);\n\n        $validator = $this->createMock(ValidatorInterface::class);\n\n        $validator->expects($this->once())\n            ->method('validate')\n            ->willReturn(new ConstraintViolationList([new ConstraintViolation('Page is invalid', null, [], '', null, '')]));\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('page', QueryPayload::class, false, false, null, false, [\n            MapQueryString::class => new MapQueryString(validationFailedStatusCode: 400),\n        ]);\n        $request = Request::create('/?page=123');\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        try {\n            $resolver->onKernelControllerArguments($event);\n            $this->fail(\\sprintf('Expected \"%s\" to be thrown.', HttpException::class));\n        } catch (HttpException $e) {\n            $validationFailedException = $e->getPrevious();\n            $this->assertSame(400, $e->getStatusCode());\n            $this->assertInstanceOf(ValidationFailedException::class, $validationFailedException);\n            $this->assertSame('Page is invalid', $validationFailedException->getViolations()[0]->getMessage());\n        }\n    }\n\n    public function testRequestPayloadValidationErrorCustomStatusCode()\n    {\n        $content = '{\"price\": 50, \"title\": [\"not a string\"]}';\n        $serializer = new Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]);\n\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->never())\n            ->method('validate');\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('invalid', RequestPayload::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(validationFailedStatusCode: 400),\n        ]);\n        $request = Request::create('/', 'POST', server: ['CONTENT_TYPE' => 'application/json'], content: $content);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        try {\n            $resolver->onKernelControllerArguments($event);\n            $this->fail(\\sprintf('Expected \"%s\" to be thrown.', HttpException::class));\n        } catch (HttpException $e) {\n            $validationFailedException = $e->getPrevious();\n            $this->assertSame(400, $e->getStatusCode());\n            $this->assertInstanceOf(ValidationFailedException::class, $validationFailedException);\n            $this->assertSame('This value should be of type string.', $validationFailedException->getViolations()[0]->getMessage());\n        }\n    }\n\n    #[DataProvider('provideBoolArgument')]\n    public function testBoolArgumentInQueryString(mixed $expectedValue, ?string $parameterValue)\n    {\n        $serializer = new Serializer([new ObjectNormalizer()]);\n        $validator = (new ValidatorBuilder())->getValidator();\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('filtered', ObjectWithBoolArgument::class, false, false, null, false, [\n            MapQueryString::class => new MapQueryString(),\n        ]);\n        $request = Request::create('/', 'GET', ['value' => $parameterValue]);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertSame($expectedValue, $event->getArguments()[0]->value);\n    }\n\n    #[DataProvider('provideBoolArgument')]\n    public function testBoolArgumentInBody(mixed $expectedValue, ?string $parameterValue)\n    {\n        $serializer = new Serializer([new ObjectNormalizer()]);\n        $validator = (new ValidatorBuilder())->getValidator();\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('filtered', ObjectWithBoolArgument::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = Request::create('/', 'POST', ['value' => $parameterValue], server: ['CONTENT_TYPE' => 'multipart/form-data']);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertSame($expectedValue, $event->getArguments()[0]->value);\n    }\n\n    public static function provideBoolArgument()\n    {\n        yield 'default value' => [null, null];\n        yield '\"0\"' => [false, '0'];\n        yield '\"false\"' => [false, 'false'];\n        yield '\"no\"' => [false, 'no'];\n        yield '\"off\"' => [false, 'off'];\n        yield '\"1\"' => [true, '1'];\n        yield '\"true\"' => [true, 'true'];\n        yield '\"yes\"' => [true, 'yes'];\n        yield '\"on\"' => [true, 'on'];\n    }\n\n    /**\n     * Boolean filtering must be disabled for content types other than form data.\n     */\n    public function testBoolArgumentInJsonBody()\n    {\n        $serializer = new Serializer([new ObjectNormalizer()]);\n        $validator = (new ValidatorBuilder())->getValidator();\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('filtered', ObjectWithBoolArgument::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = Request::create('/', 'POST', ['value' => 'off'], server: ['CONTENT_TYPE' => 'application/json']);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertTrue($event->getArguments()[0]->value);\n    }\n\n    public function testConfigKeyForQueryString()\n    {\n        $serializer = new Serializer([new ObjectNormalizer()]);\n        $validator = (new ValidatorBuilder())->getValidator();\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('filtered', QueryPayload::class, false, false, null, false, [\n            MapQueryString::class => new MapQueryString(key: 'value'),\n        ]);\n        $request = Request::create('/', 'GET', ['value' => ['page' => 1.0]]);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertInstanceOf(QueryPayload::class, $event->getArguments()[0]);\n        $this->assertSame(1.0, $event->getArguments()[0]->page);\n    }\n\n    public function testMapRequestPayloadVariadic()\n    {\n        $input = [\n            ['price' => '50'],\n            ['price' => '23'],\n        ];\n        $payload = [\n            new RequestPayload(50),\n            new RequestPayload(23),\n        ];\n\n        $serializer = new Serializer([new ArrayDenormalizer(), new ObjectNormalizer()], ['json' => new JsonEncoder()]);\n\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->once())\n            ->method('validate')\n            ->willReturn(new ConstraintViolationList());\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('prices', RequestPayload::class, true, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = Request::create('/', 'POST', $input);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertEquals($payload, $event->getArguments());\n    }\n\n    public function testMapRequestPayloadVariadicJson()\n    {\n        $payload = [\n            new RequestPayload(50),\n            new RequestPayload(23),\n        ];\n\n        $serializer = new Serializer([new ArrayDenormalizer(), new ObjectNormalizer()], ['json' => new JsonEncoder()]);\n\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->once())\n            ->method('validate')\n            ->willReturn(new ConstraintViolationList());\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('prices', RequestPayload::class, true, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = Request::create('/', 'POST', server: ['CONTENT_TYPE' => 'application/json'], content: '[{\"price\": 50}, {\"price\": 23}]');\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertEquals($payload, $event->getArguments());\n    }\n\n    public function testMapRequestPayloadWithUploadedFiles()\n    {\n        $image = new UploadedFile(self::FIXTURES_BASE_PATH.'/file-small.txt', 'file-small.txt');\n        $input = ['price' => '50'];\n        $files = ['image' => $image];\n        $payload = new RequestPayloadWithFile(50);\n        $payload->image = $image;\n\n        $serializer = new Serializer([new ObjectNormalizer()]);\n\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->once())\n            ->method('validate')\n            ->willReturn(new ConstraintViolationList());\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator);\n\n        $argument = new ArgumentMetadata('data', RequestPayloadWithFile::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = Request::create('/', 'POST', $input, [], $files);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $argument = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static function () {}, $argument, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertEquals([$payload], $event->getArguments());\n    }\n\n    public function testExpressionAsValidationGroup()\n    {\n        $content = '{\"price\": 24}';\n\n        $serializer = new Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]);\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->once())\n            ->method('validate')\n            ->with(new RequestPayload(24.0), null, 'foo');\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator, expressionLanguage: new ExpressionLanguage());\n\n        $argument = new ArgumentMetadata('payload', RequestPayload::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(validationGroups: new Expression('args[\"foo\"]')),\n        ]);\n\n        $request = Request::create('/{foo}/{bar}/{baz}', 'POST', server: ['CONTENT_TYPE' => 'application/json'], content: $content);\n\n        $arguments = (array) $resolver->resolve($request, $argument);\n        array_unshift($arguments, 'foo', 15, 1.23);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $controllerEvent = new ControllerEvent($kernel, [new BasicTypesController(), 'action'], $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $event = new ControllerArgumentsEvent($kernel, $controllerEvent, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n    }\n\n    public function testExpressionAsValidationGroupCanUseController()\n    {\n        $content = '{\"price\": 24}';\n\n        $serializer = new Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]);\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->once())\n            ->method('validate')\n            ->with(new RequestPayload(24.0), null, 'foo');\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator, expressionLanguage: new ExpressionLanguage());\n\n        $argument = new ArgumentMetadata('payload', RequestPayload::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(validationGroups: new Expression('this ? args[\"foo\"] : \"bar\"')),\n        ]);\n\n        $request = Request::create('/{foo}/{bar}/{baz}', 'POST', server: ['CONTENT_TYPE' => 'application/json'], content: $content);\n\n        $arguments = (array) $resolver->resolve($request, $argument);\n        array_unshift($arguments, 'foo', 15, 1.23);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $controllerEvent = new ControllerEvent($kernel, [new BasicTypesController(), 'action'], $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $event = new ControllerArgumentsEvent($kernel, $controllerEvent, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n    }\n\n    public function testClosureAsValidationGroup()\n    {\n        $content = '{\"price\": 24}';\n\n        $serializer = new Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]);\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->once())\n            ->method('validate')\n            ->with(new RequestPayload(24.0), null, 'foo');\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator, expressionLanguage: new ExpressionLanguage());\n\n        $asserted = false;\n        $self = $this;\n\n        $argument = new ArgumentMetadata('payload', RequestPayload::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(validationGroups: static function (array $args, Request $request, ?object $controller) use (&$asserted, $self): string {\n                $self->assertInstanceOf(BasicTypesController::class, $controller);\n                $asserted = true;\n\n                return $args['foo'];\n            }),\n        ]);\n\n        $request = Request::create('/{foo}/{bar}/{baz}', 'POST', server: ['CONTENT_TYPE' => 'application/json'], content: $content);\n\n        $arguments = (array) $resolver->resolve($request, $argument);\n        array_unshift($arguments, 'foo', 15, 1.23);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $controllerEvent = new ControllerEvent($kernel, [new BasicTypesController(), 'action'], $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $event = new ControllerArgumentsEvent($kernel, $controllerEvent, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        $this->assertTrue($asserted);\n    }\n\n    public function testExpressionAsValidationGroupForQueryString()\n    {\n        $serializer = new Serializer([new ObjectNormalizer()]);\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->once())\n            ->method('validate')\n            ->with(new QueryPayload(1.0), null, 'foo')\n            ->willReturn(new ConstraintViolationList());\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator, expressionLanguage: new ExpressionLanguage());\n\n        $argument = new ArgumentMetadata('payload', QueryPayload::class, false, false, null, false, [\n            MapQueryString::class => new MapQueryString(validationGroups: new Expression('args[\"foo\"]')),\n        ]);\n\n        $request = Request::create('/', 'GET', ['page' => 1.0]);\n\n        $arguments = (array) $resolver->resolve($request, $argument);\n        array_unshift($arguments, 'foo', 15, 1.23);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $controllerEvent = new ControllerEvent($kernel, [new BasicTypesController(), 'action'], $request, HttpKernelInterface::MAIN_REQUEST);\n        $event = new ControllerArgumentsEvent($kernel, $controllerEvent, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n    }\n\n    public function testNestedExpressionsInValidationGroupsAreNotSupported()\n    {\n        $content = '{\"price\": 24}';\n\n        $serializer = new Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]);\n        $validator = $this->createMock(ValidatorInterface::class);\n        $validator->expects($this->never())\n            ->method('validate');\n\n        $resolver = new RequestPayloadValueResolver($serializer, $validator, expressionLanguage: new ExpressionLanguage());\n\n        $argument = new ArgumentMetadata('payload', RequestPayload::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(validationGroups: ['foo', new Expression('args[\"foo\"]')]),\n        ]);\n\n        $request = Request::create('/', 'POST', server: ['CONTENT_TYPE' => 'application/json'], content: $content);\n        $arguments = (array) $resolver->resolve($request, $argument);\n        array_unshift($arguments, 'foo', 15, 1.23);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $controllerEvent = new ControllerEvent($kernel, [new BasicTypesController(), 'action'], $request, HttpKernelInterface::MAIN_REQUEST);\n        $event = new ControllerArgumentsEvent($kernel, $controllerEvent, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $this->expectException(\\LogicException::class);\n\n        $resolver->onKernelControllerArguments($event);\n    }\n\n    public function testMapRequestPayloadWithPreParsedJsonIntCoercesToFloat()\n    {\n        $serializer = new Serializer(\n            [new ObjectNormalizer(null, null, null, new ReflectionExtractor())],\n            ['json' => new JsonEncoder()]\n        );\n\n        $resolver = new RequestPayloadValueResolver($serializer);\n\n        $argument = new ArgumentMetadata('payload', RequestPayload::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = new Request([], ['price' => 0], [], [], [], ['CONTENT_TYPE' => 'application/json']);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static fn () => null, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        /** @var RequestPayload $payload */\n        [$payload] = $event->getArguments();\n        $this->assertInstanceOf(RequestPayload::class, $payload);\n        $this->assertSame(0.0, $payload->price);\n    }\n\n    public function testMapRequestPayloadWithFormDataCoercesStringToBool()\n    {\n        $serializer = new Serializer(\n            [new ObjectNormalizer(null, null, null, new ReflectionExtractor())],\n            []\n        );\n\n        $resolver = new RequestPayloadValueResolver($serializer);\n\n        $argument = new ArgumentMetadata('payload', FormPayloadWithBool::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = new Request([], ['active' => '0'], [], [], [], ['CONTENT_TYPE' => 'application/x-www-form-urlencoded']);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static fn () => null, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        /** @var FormPayloadWithBool $payload */\n        [$payload] = $event->getArguments();\n        $this->assertInstanceOf(FormPayloadWithBool::class, $payload);\n        $this->assertFalse($payload->active);\n    }\n\n    public function testMapRequestPayloadWithJsonContentTypeStringValuesCoercesToBool()\n    {\n        $serializer = new Serializer(\n            [new ObjectNormalizer(null, null, null, new ReflectionExtractor())],\n            []\n        );\n\n        $resolver = new RequestPayloadValueResolver($serializer);\n\n        $argument = new ArgumentMetadata('payload', FormPayloadWithBool::class, false, false, null, false, [\n            MapRequestPayload::class => new MapRequestPayload(),\n        ]);\n        $request = new Request([], ['active' => '0'], [], [], [], ['CONTENT_TYPE' => 'application/json']);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $arguments = $resolver->resolve($request, $argument);\n        $event = new ControllerArgumentsEvent($kernel, static fn () => null, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $resolver->onKernelControllerArguments($event);\n\n        /** @var FormPayloadWithBool $payload */\n        [$payload] = $event->getArguments();\n        $this->assertInstanceOf(FormPayloadWithBool::class, $payload);\n        $this->assertFalse($payload->active);\n    }\n}\n\nclass RequestPayload\n{\n    #[Assert\\Length(min: 10, groups: ['strict'])]\n    public string $title;\n\n    public function __construct(public readonly float $price)\n    {\n    }\n}\n\nclass RequestPayloadWithFile extends RequestPayload\n{\n    public ?UploadedFile $image = null;\n}\n\ninterface SerializerDenormalizer extends SerializerInterface, DenormalizerInterface\n{\n}\n\nclass QueryPayload\n{\n    public function __construct(public readonly float $page)\n    {\n    }\n}\n\nclass User\n{\n    public function __construct(\n        #[Assert\\NotBlank, Assert\\Email]\n        private string $email,\n        #[Assert\\NotBlank]\n        private string $password,\n    ) {\n    }\n\n    public function getEmail(): string\n    {\n        return $this->email;\n    }\n\n    public function getPassword(): string\n    {\n        return $this->password;\n    }\n}\n\nclass RequestPayloadWithBackedEnum\n{\n    public function __construct(public readonly RequestMethod $method)\n    {\n    }\n}\n\nenum RequestMethod: string\n{\n    case GET = 'GET';\n    case POST = 'POST';\n}\n\nclass ObjectWithBoolArgument\n{\n    public function __construct(public readonly ?bool $value = null)\n    {\n    }\n}\n\nclass FormPayloadWithBool\n{\n    public function __construct(public readonly bool $active)\n    {\n    }\n}\n\nclass RequestPayloadDenormalizer implements DenormalizerInterface\n{\n    public function __construct(private RequestPayload $payload)\n    {\n    }\n\n    public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed\n    {\n        return $this->payload;\n    }\n\n    public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool\n    {\n        return RequestPayload::class === $type;\n    }\n\n    public function getSupportedTypes(?string $format = null): array\n    {\n        return [RequestPayload::class => true];\n    }\n}\n"
  },
  {
    "path": "Tests/Controller/ArgumentResolver/RequestValueResolverTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Controller\\ArgumentResolver;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\BrowserKit\\Request as RandomRequest;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\RequestValueResolver;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Exception\\NearMissValueResolverException;\n\nclass RequestValueResolverTest extends TestCase\n{\n    public function testSameRequestReturned()\n    {\n        $resolver = new RequestValueResolver();\n        $expectedRequest = Request::create('/');\n        $actualRequest = $resolver->resolve($expectedRequest, new ArgumentMetadata('request', Request::class, false, false, null));\n        self::assertCount(1, $actualRequest);\n        self::assertSame($expectedRequest, $actualRequest[0] ?? null);\n    }\n\n    public function testRequestIsNotResolvedForRandomClass()\n    {\n        $resolver = new RequestValueResolver();\n        $expectedRequest = Request::create('/');\n        $actualRequest = $resolver->resolve($expectedRequest, new ArgumentMetadata('request', self::class, false, false, null));\n        self::assertCount(0, $actualRequest);\n    }\n\n    public function testExceptionThrownForRandomRequestClass()\n    {\n        $resolver = new RequestValueResolver();\n        $expectedRequest = Request::create('/');\n        $this->expectException(NearMissValueResolverException::class);\n        $resolver->resolve($expectedRequest, new ArgumentMetadata('request', RandomRequest::class, false, false, null));\n    }\n}\n"
  },
  {
    "path": "Tests/Controller/ArgumentResolver/ServiceValueResolverTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Controller\\ArgumentResolver;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\ServiceLocator;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\ServiceValueResolver;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\DependencyInjection\\RegisterControllerArgumentLocatorsPass;\nuse Symfony\\Component\\HttpKernel\\Exception\\NearMissValueResolverException;\n\nclass ServiceValueResolverTest extends TestCase\n{\n    public function testDoNotSupportWhenControllerDoNotExists()\n    {\n        $resolver = new ServiceValueResolver(new ServiceLocator([]));\n        $argument = new ArgumentMetadata('dummy', DummyService::class, false, false, null);\n        $request = $this->requestWithAttributes(['_controller' => 'my_controller']);\n\n        $this->assertSame([], $resolver->resolve($request, $argument));\n    }\n\n    public function testExistingController()\n    {\n        $resolver = new ServiceValueResolver(new ServiceLocator([\n            'App\\\\Controller\\\\Mine::method' => static fn () => new ServiceLocator([\n                'dummy' => static fn () => new DummyService(),\n            ]),\n        ]));\n\n        $request = $this->requestWithAttributes(['_controller' => 'App\\\\Controller\\\\Mine::method']);\n        $argument = new ArgumentMetadata('dummy', DummyService::class, false, false, null);\n\n        $this->assertEquals([new DummyService()], $resolver->resolve($request, $argument));\n    }\n\n    public function testExistingControllerWithATrailingBackSlash()\n    {\n        $resolver = new ServiceValueResolver(new ServiceLocator([\n            'App\\\\Controller\\\\Mine::method' => static fn () => new ServiceLocator([\n                'dummy' => static fn () => new DummyService(),\n            ]),\n        ]));\n\n        $request = $this->requestWithAttributes(['_controller' => '\\\\App\\\\Controller\\\\Mine::method']);\n        $argument = new ArgumentMetadata('dummy', DummyService::class, false, false, null);\n\n        $this->assertEquals([new DummyService()], $resolver->resolve($request, $argument));\n    }\n\n    public function testExistingControllerWithMethodNameStartUppercase()\n    {\n        $resolver = new ServiceValueResolver(new ServiceLocator([\n            'App\\\\Controller\\\\Mine::method' => static fn () => new ServiceLocator([\n                'dummy' => static fn () => new DummyService(),\n            ]),\n        ]));\n        $request = $this->requestWithAttributes(['_controller' => 'App\\\\Controller\\\\Mine::Method']);\n        $argument = new ArgumentMetadata('dummy', DummyService::class, false, false, null);\n\n        $this->assertEquals([new DummyService()], $resolver->resolve($request, $argument));\n    }\n\n    public function testControllerNameIsAnArray()\n    {\n        $resolver = new ServiceValueResolver(new ServiceLocator([\n            'App\\\\Controller\\\\Mine::method' => static fn () => new ServiceLocator([\n                'dummy' => static fn () => new DummyService(),\n            ]),\n        ]));\n\n        $request = $this->requestWithAttributes(['_controller' => ['App\\\\Controller\\\\Mine', 'method']]);\n        $argument = new ArgumentMetadata('dummy', DummyService::class, false, false, null);\n\n        $this->assertEquals([new DummyService()], $resolver->resolve($request, $argument));\n    }\n\n    public function testErrorIsTruncated()\n    {\n        $this->expectException(NearMissValueResolverException::class);\n        $this->expectExceptionMessage('Cannot autowire argument $dummy required by \"Symfony\\Component\\HttpKernel\\Tests\\Controller\\ArgumentResolver\\DummyController::index()\": it references class \"Symfony\\Component\\HttpKernel\\Tests\\Controller\\ArgumentResolver\\DummyService\" but no such service exists.');\n        $container = new ContainerBuilder();\n        $container->addCompilerPass(new RegisterControllerArgumentLocatorsPass());\n\n        $container->register('argument_resolver.service', ServiceValueResolver::class)->addArgument(null)->setPublic(true);\n        $container->register(DummyController::class)->addTag('controller.service_arguments')->setPublic(true);\n\n        $container->compile();\n\n        $request = $this->requestWithAttributes(['_controller' => [DummyController::class, 'index']]);\n        $argument = new ArgumentMetadata('dummy', DummyService::class, false, false, null);\n        $container->get('argument_resolver.service')->resolve($request, $argument)->current();\n    }\n\n    private function requestWithAttributes(array $attributes)\n    {\n        $request = Request::create('/');\n\n        foreach ($attributes as $name => $value) {\n            $request->attributes->set($name, $value);\n        }\n\n        return $request;\n    }\n}\n\nclass DummyService\n{\n}\n\nclass DummyController\n{\n    public function index(DummyService $dummy)\n    {\n    }\n}\n"
  },
  {
    "path": "Tests/Controller/ArgumentResolver/TraceableValueResolverTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Controller\\ArgumentResolver;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\TraceableValueResolver;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\Stopwatch\\Stopwatch;\n\nclass TraceableValueResolverTest extends TestCase\n{\n    public function testTimingsInResolve()\n    {\n        $stopwatch = new Stopwatch();\n        $resolver = new TraceableValueResolver(new ResolverStub(), $stopwatch);\n        $argument = new ArgumentMetadata('dummy', 'string', false, false, null);\n        $request = new Request();\n\n        $iterable = $resolver->resolve($request, $argument);\n\n        foreach ($iterable as $index => $resolved) {\n            $event = $stopwatch->getEvent(ResolverStub::class.'::resolve');\n            $this->assertTrue($event->isStarted());\n            $this->assertSame([], $event->getPeriods());\n            switch ($index) {\n                case 0:\n                    $this->assertEquals('first', $resolved);\n                    break;\n                case 1:\n                    $this->assertEquals('second', $resolved);\n                    break;\n            }\n        }\n\n        $event = $stopwatch->getEvent(ResolverStub::class.'::resolve');\n        $this->assertCount(1, $event->getPeriods());\n    }\n}\n\nclass ResolverStub implements ValueResolverInterface\n{\n    public function resolve(Request $request, ArgumentMetadata $argument): iterable\n    {\n        yield 'first';\n        yield 'second';\n    }\n}\n"
  },
  {
    "path": "Tests/Controller/ArgumentResolver/UidValueResolverTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Controller\\ArgumentResolver;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\UidValueResolver;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;\nuse Symfony\\Component\\Uid\\AbstractUid;\nuse Symfony\\Component\\Uid\\Factory\\UlidFactory;\nuse Symfony\\Component\\Uid\\Ulid;\nuse Symfony\\Component\\Uid\\UuidV1;\nuse Symfony\\Component\\Uid\\UuidV4;\n\nclass UidValueResolverTest extends TestCase\n{\n    #[DataProvider('provideSupports')]\n    public function testSupports(bool $expected, Request $request, ArgumentMetadata $argument)\n    {\n        $this->assertCount((int) $expected, (new UidValueResolver())->resolve($request, $argument));\n    }\n\n    public static function provideSupports()\n    {\n        return [\n            'Variadic argument' => [false, new Request([], [], ['foo' => (string) $uuidV4 = new UuidV4()]), new ArgumentMetadata('foo', UuidV4::class, true, false, null)],\n            'No attribute for argument' => [false, new Request([], [], []), new ArgumentMetadata('foo', UuidV4::class, false, false, null)],\n            'Attribute is not a string' => [false, new Request([], [], ['foo' => ['bar']]), new ArgumentMetadata('foo', UuidV4::class, false, false, null)],\n            'Argument has no type' => [false, new Request([], [], ['foo' => (string) $uuidV4]), new ArgumentMetadata('foo', null, false, false, null)],\n            'Argument type is not a class' => [false, new Request([], [], ['foo' => (string) $uuidV4]), new ArgumentMetadata('foo', 'string', false, false, null)],\n            'Argument type is not a subclass of AbstractUid' => [false, new Request([], [], ['foo' => (string) $uuidV4]), new ArgumentMetadata('foo', UlidFactory::class, false, false, null)],\n            'AbstractUid is not supported' => [false, new Request([], [], ['foo' => (string) $uuidV4]), new ArgumentMetadata('foo', AbstractUid::class, false, false, null)],\n            'Known subclass' => [true, new Request([], [], ['foo' => (string) $uuidV4]), new ArgumentMetadata('foo', UuidV4::class, false, false, null)],\n            'Format does not matter' => [true, new Request([], [], ['foo' => (string) $uuidV4]), new ArgumentMetadata('foo', Ulid::class, false, false, null)],\n        ];\n    }\n\n    #[DataProvider('provideResolveOK')]\n    public function testResolveOK(AbstractUid $expected, string $requestUid)\n    {\n        $this->assertEquals([$expected], (new UidValueResolver())->resolve(\n            new Request([], [], ['id' => $requestUid]),\n            new ArgumentMetadata('id', $expected::class, false, false, null)\n        ));\n    }\n\n    public static function provideResolveOK()\n    {\n        return [\n            [$uuidV1 = new UuidV1(), (string) $uuidV1],\n            [$uuidV1, $uuidV1->toBase58()],\n            [$uuidV1, $uuidV1->toBase32()],\n            [$ulid = Ulid::fromBase32('01FQC6Y03WDZ73DQY9RXQMPHB1'), (string) $ulid],\n            [$ulid, $ulid->toBase58()],\n            [$ulid, $ulid->toRfc4122()],\n            [$customUid = new TestCustomUid(), (string) $customUid],\n            [$customUid, $customUid->toBase58()],\n            [$customUid, $customUid->toBase32()],\n        ];\n    }\n\n    #[DataProvider('provideResolveKO')]\n    public function testResolveKO(string $requestUid, string $argumentType)\n    {\n        $this->expectException(NotFoundHttpException::class);\n        $this->expectExceptionMessage('The uid for the \"id\" parameter is invalid.');\n\n        (new UidValueResolver())->resolve(\n            new Request([], [], ['id' => $requestUid]),\n            new ArgumentMetadata('id', $argumentType, false, false, null)\n        );\n    }\n\n    public static function provideResolveKO()\n    {\n        return [\n            'Bad value for UUID' => ['ccc', UuidV1::class],\n            'Bad value for ULID' => ['ccc', Ulid::class],\n            'Bad value for custom UID' => ['ccc', TestCustomUid::class],\n            'Bad UUID version' => [(string) new UuidV4(), UuidV1::class],\n        ];\n    }\n\n    public function testResolveAbstractClass()\n    {\n        $this->expectException(\\Error::class);\n        $this->expectExceptionMessage('Cannot instantiate abstract class Symfony\\Component\\HttpKernel\\Tests\\Controller\\ArgumentResolver\\TestAbstractCustomUid');\n\n        (new UidValueResolver())->resolve(\n            new Request([], [], ['id' => (string) new UuidV1()]),\n            new ArgumentMetadata('id', TestAbstractCustomUid::class, false, false, null)\n        );\n    }\n}\n\nclass TestCustomUid extends UuidV1\n{\n}\n\nabstract class TestAbstractCustomUid extends UuidV1\n{\n}\n"
  },
  {
    "path": "Tests/Controller/ArgumentResolver/UploadedFileValueResolverTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Controller\\ArgumentResolver;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\File\\UploadedFile;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Attribute\\MapUploadedFile;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\RequestPayloadValueResolver;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsEvent;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\Serializer\\Serializer;\nuse Symfony\\Component\\Validator\\Constraints as Assert;\nuse Symfony\\Component\\Validator\\Exception\\ValidationFailedException;\nuse Symfony\\Component\\Validator\\ValidatorBuilder;\n\nclass UploadedFileValueResolverTest extends TestCase\n{\n    private const FIXTURES_BASE_PATH = __DIR__.'/../../Fixtures/Controller/ArgumentResolver/UploadedFile';\n\n    #[DataProvider('provideContext')]\n    public function testDefaults(RequestPayloadValueResolver $resolver, Request $request)\n    {\n        $attribute = new MapUploadedFile();\n        $argument = new ArgumentMetadata(\n            'foo',\n            UploadedFile::class,\n            false,\n            false,\n            null,\n            false,\n            [$attribute::class => $attribute]\n        );\n        $event = new ControllerArgumentsEvent(\n            $this->createStub(HttpKernelInterface::class),\n            static function () {},\n            $resolver->resolve($request, $argument),\n            $request,\n            HttpKernelInterface::MAIN_REQUEST\n        );\n        $resolver->onKernelControllerArguments($event);\n\n        /** @var UploadedFile $data */\n        $data = $event->getArguments()[0];\n\n        $this->assertInstanceOf(UploadedFile::class, $data);\n        $this->assertSame('file-small.txt', $data->getFilename());\n        $this->assertSame(36, $data->getSize());\n    }\n\n    #[DataProvider('provideContext')]\n    public function testEmpty(RequestPayloadValueResolver $resolver, Request $request)\n    {\n        $attribute = new MapUploadedFile();\n        $argument = new ArgumentMetadata(\n            'qux',\n            UploadedFile::class,\n            false,\n            false,\n            null,\n            false,\n            [$attribute::class => $attribute]\n        );\n        $event = new ControllerArgumentsEvent(\n            $this->createStub(HttpKernelInterface::class),\n            static function () {},\n            $resolver->resolve($request, $argument),\n            $request,\n            HttpKernelInterface::MAIN_REQUEST\n        );\n\n        $this->expectException(HttpException::class);\n\n        $resolver->onKernelControllerArguments($event);\n    }\n\n    public function testEmptyArrayUploadedFileArgument()\n    {\n        $resolver = new RequestPayloadValueResolver(\n            new Serializer(),\n            (new ValidatorBuilder())->getValidator()\n        );\n        $request = Request::create(\n            '/',\n            'POST',\n            files: [\n                'qux' => [],\n            ],\n            server: ['HTTP_CONTENT_TYPE' => 'multipart/form-data']\n        );\n\n        $attribute = new MapUploadedFile();\n        $argument = new ArgumentMetadata(\n            'qux',\n            UploadedFile::class,\n            false,\n            false,\n            null,\n            false,\n            [$attribute::class => $attribute]\n        );\n        $event = new ControllerArgumentsEvent(\n            $this->createStub(HttpKernelInterface::class),\n            static function () {},\n            $resolver->resolve($request, $argument),\n            $request,\n            HttpKernelInterface::MAIN_REQUEST\n        );\n\n        $this->expectException(HttpException::class);\n\n        $resolver->onKernelControllerArguments($event);\n    }\n\n    #[DataProvider('provideContext')]\n    public function testEmptyArrayArgument(RequestPayloadValueResolver $resolver, Request $request)\n    {\n        $attribute = new MapUploadedFile();\n        $argument = new ArgumentMetadata(\n            'qux',\n            'array',\n            false,\n            false,\n            null,\n            false,\n            [$attribute::class => $attribute]\n        );\n        $event = new ControllerArgumentsEvent(\n            $this->createStub(HttpKernelInterface::class),\n            static function () {},\n            $resolver->resolve($request, $argument),\n            $request,\n            HttpKernelInterface::MAIN_REQUEST\n        );\n\n        $resolver->onKernelControllerArguments($event);\n        $data = $event->getArguments()[0];\n\n        $this->assertSame([], $data);\n    }\n\n    #[DataProvider('provideContext')]\n    public function testCustomName(RequestPayloadValueResolver $resolver, Request $request)\n    {\n        $attribute = new MapUploadedFile(name: 'bar');\n        $argument = new ArgumentMetadata(\n            'foo',\n            UploadedFile::class,\n            false,\n            false,\n            null,\n            false,\n            [$attribute::class => $attribute]\n        );\n        $event = new ControllerArgumentsEvent(\n            $this->createStub(HttpKernelInterface::class),\n            static function () {},\n            $resolver->resolve($request, $argument),\n            $request,\n            HttpKernelInterface::MAIN_REQUEST\n        );\n        $resolver->onKernelControllerArguments($event);\n\n        /** @var UploadedFile $data */\n        $data = $event->getArguments()[0];\n\n        $this->assertInstanceOf(UploadedFile::class, $data);\n        $this->assertSame('file-big.txt', $data->getFilename());\n        $this->assertSame(71, $data->getSize());\n    }\n\n    #[DataProvider('provideContext')]\n    public function testConstraintsWithoutViolation(RequestPayloadValueResolver $resolver, Request $request)\n    {\n        $attribute = new MapUploadedFile(constraints: new Assert\\File(maxSize: 100));\n        $argument = new ArgumentMetadata(\n            'bar',\n            UploadedFile::class,\n            false,\n            false,\n            null,\n            false,\n            [$attribute::class => $attribute]\n        );\n        $event = new ControllerArgumentsEvent(\n            $this->createStub(HttpKernelInterface::class),\n            static function () {},\n            $resolver->resolve($request, $argument),\n            $request,\n            HttpKernelInterface::MAIN_REQUEST\n        );\n        $resolver->onKernelControllerArguments($event);\n\n        /** @var UploadedFile $data */\n        $data = $event->getArguments()[0];\n\n        $this->assertInstanceOf(UploadedFile::class, $data);\n        $this->assertSame('file-big.txt', $data->getFilename());\n        $this->assertSame(71, $data->getSize());\n    }\n\n    #[DataProvider('provideContext')]\n    public function testConstraintsWithViolation(RequestPayloadValueResolver $resolver, Request $request)\n    {\n        $attribute = new MapUploadedFile(constraints: new Assert\\File(maxSize: 50));\n        $argument = new ArgumentMetadata(\n            'bar',\n            UploadedFile::class,\n            false,\n            false,\n            null,\n            false,\n            [$attribute::class => $attribute]\n        );\n        $event = new ControllerArgumentsEvent(\n            $this->createStub(HttpKernelInterface::class),\n            static function () {},\n            $resolver->resolve($request, $argument),\n            $request,\n            HttpKernelInterface::MAIN_REQUEST\n        );\n\n        $this->expectException(HttpException::class);\n        $this->expectExceptionMessageMatches('/^The file is too large/');\n\n        $resolver->onKernelControllerArguments($event);\n    }\n\n    #[DataProvider('provideContext')]\n    public function testConstraintsViolationHasArgumentNameAsPropertyPath(RequestPayloadValueResolver $resolver, Request $request)\n    {\n        $attribute = new MapUploadedFile(constraints: new Assert\\File(maxSize: 50));\n        $argument = new ArgumentMetadata(\n            'bar',\n            UploadedFile::class,\n            false,\n            false,\n            null,\n            false,\n            [$attribute::class => $attribute]\n        );\n        $event = new ControllerArgumentsEvent(\n            $this->createStub(HttpKernelInterface::class),\n            static function () {},\n            $resolver->resolve($request, $argument),\n            $request,\n            HttpKernelInterface::MAIN_REQUEST\n        );\n\n        try {\n            $resolver->onKernelControllerArguments($event);\n            $this->fail(\\sprintf('Expected \"%s\" to be thrown.', HttpException::class));\n        } catch (HttpException $e) {\n            $validationFailedException = $e->getPrevious();\n            $this->assertInstanceOf(ValidationFailedException::class, $validationFailedException);\n            $this->assertSame('bar', $validationFailedException->getViolations()[0]->getPropertyPath());\n        }\n    }\n\n    #[DataProvider('provideContext')]\n    public function testMultipleFilesArray(RequestPayloadValueResolver $resolver, Request $request)\n    {\n        $attribute = new MapUploadedFile();\n        $argument = new ArgumentMetadata(\n            'baz',\n            UploadedFile::class,\n            false,\n            false,\n            null,\n            false,\n            [$attribute::class => $attribute]\n        );\n        $event = new ControllerArgumentsEvent(\n            $this->createStub(HttpKernelInterface::class),\n            static function () {},\n            $resolver->resolve($request, $argument),\n            $request,\n            HttpKernelInterface::MAIN_REQUEST\n        );\n        $resolver->onKernelControllerArguments($event);\n\n        /** @var UploadedFile[] $data */\n        $data = $event->getArguments()[0];\n\n        $this->assertCount(2, $data);\n        $this->assertSame('file-small.txt', $data[0]->getFilename());\n        $this->assertSame(36, $data[0]->getSize());\n        $this->assertSame('file-big.txt', $data[1]->getFilename());\n        $this->assertSame(71, $data[1]->getSize());\n    }\n\n    #[DataProvider('provideContext')]\n    public function testMultipleFilesArrayConstraints(RequestPayloadValueResolver $resolver, Request $request)\n    {\n        $attribute = new MapUploadedFile(constraints: new Assert\\File(maxSize: 50));\n        $argument = new ArgumentMetadata(\n            'baz',\n            UploadedFile::class,\n            false,\n            false,\n            null,\n            false,\n            [$attribute::class => $attribute]\n        );\n        $event = new ControllerArgumentsEvent(\n            $this->createStub(HttpKernelInterface::class),\n            static function () {},\n            $resolver->resolve($request, $argument),\n            $request,\n            HttpKernelInterface::MAIN_REQUEST\n        );\n\n        $this->expectException(HttpException::class);\n        $this->expectExceptionMessageMatches('/^The file is too large/');\n\n        $resolver->onKernelControllerArguments($event);\n    }\n\n    #[DataProvider('provideContext')]\n    public function testSingleFileVariadic(RequestPayloadValueResolver $resolver, Request $request)\n    {\n        $attribute = new MapUploadedFile();\n        $argument = new ArgumentMetadata(\n            'foo',\n            UploadedFile::class,\n            true,\n            false,\n            null,\n            false,\n            [$attribute::class => $attribute]\n        );\n        $event = new ControllerArgumentsEvent(\n            $this->createStub(HttpKernelInterface::class),\n            static function () {},\n            $resolver->resolve($request, $argument),\n            $request,\n            HttpKernelInterface::MAIN_REQUEST\n        );\n        $resolver->onKernelControllerArguments($event);\n\n        /** @var UploadedFile[] $data */\n        $data = $event->getArguments();\n\n        $this->assertCount(1, $data);\n        $this->assertSame('file-small.txt', $data[0]->getFilename());\n        $this->assertSame(36, $data[0]->getSize());\n    }\n\n    #[DataProvider('provideContext')]\n    public function testMultipleFilesVariadic(RequestPayloadValueResolver $resolver, Request $request)\n    {\n        $attribute = new MapUploadedFile();\n        $argument = new ArgumentMetadata(\n            'baz',\n            UploadedFile::class,\n            true,\n            false,\n            null,\n            false,\n            [$attribute::class => $attribute]\n        );\n        $event = new ControllerArgumentsEvent(\n            $this->createStub(HttpKernelInterface::class),\n            static function () {},\n            $resolver->resolve($request, $argument),\n            $request,\n            HttpKernelInterface::MAIN_REQUEST\n        );\n        $resolver->onKernelControllerArguments($event);\n\n        /** @var UploadedFile[] $data */\n        $data = $event->getArguments();\n\n        $this->assertCount(2, $data);\n        $this->assertSame('file-small.txt', $data[0]->getFilename());\n        $this->assertSame(36, $data[0]->getSize());\n        $this->assertSame('file-big.txt', $data[1]->getFilename());\n        $this->assertSame(71, $data[1]->getSize());\n    }\n\n    #[DataProvider('provideContext')]\n    public function testMultipleFilesVariadicConstraints(RequestPayloadValueResolver $resolver, Request $request)\n    {\n        $attribute = new MapUploadedFile(constraints: new Assert\\File(maxSize: 50));\n        $argument = new ArgumentMetadata(\n            'baz',\n            UploadedFile::class,\n            true,\n            false,\n            null,\n            false,\n            [$attribute::class => $attribute]\n        );\n        $event = new ControllerArgumentsEvent(\n            $this->createStub(HttpKernelInterface::class),\n            static function () {},\n            $resolver->resolve($request, $argument),\n            $request,\n            HttpKernelInterface::MAIN_REQUEST\n        );\n\n        $this->expectException(HttpException::class);\n        $this->expectExceptionMessageMatches('/^The file is too large/');\n\n        $resolver->onKernelControllerArguments($event);\n    }\n\n    #[DataProvider('provideContext')]\n    public function testShouldAllowEmptyWhenNullable(RequestPayloadValueResolver $resolver, Request $request)\n    {\n        $attribute = new MapUploadedFile();\n        $argument = new ArgumentMetadata(\n            'qux',\n            UploadedFile::class,\n            false,\n            false,\n            null,\n            true,\n            [$attribute::class => $attribute]\n        );\n        /** @var HttpKernelInterface&MockObject $httpKernel */\n        $httpKernel = $this->createStub(HttpKernelInterface::class);\n        $event = new ControllerArgumentsEvent(\n            $httpKernel,\n            static function () {},\n            $resolver->resolve($request, $argument),\n            $request,\n            HttpKernelInterface::MAIN_REQUEST\n        );\n        $resolver->onKernelControllerArguments($event);\n        $data = $event->getArguments()[0];\n\n        $this->assertNull($data);\n    }\n\n    #[DataProvider('provideContext')]\n    public function testShouldAllowEmptyWhenNullableArray(RequestPayloadValueResolver $resolver, Request $request)\n    {\n        $attribute = new MapUploadedFile();\n        $argument = new ArgumentMetadata(\n            'qux',\n            'array',\n            false,\n            false,\n            null,\n            true,\n            [$attribute::class => $attribute]\n        );\n        /** @var HttpKernelInterface&MockObject $httpKernel */\n        $httpKernel = $this->createStub(HttpKernelInterface::class);\n        $event = new ControllerArgumentsEvent(\n            $httpKernel,\n            static function () {},\n            $resolver->resolve($request, $argument),\n            $request,\n            HttpKernelInterface::MAIN_REQUEST\n        );\n        $resolver->onKernelControllerArguments($event);\n        $data = $event->getArguments()[0];\n\n        $this->assertNull($data);\n    }\n\n    #[DataProvider('provideContext')]\n    public function testShouldAllowEmptyWhenHasDefaultValue(RequestPayloadValueResolver $resolver, Request $request)\n    {\n        $attribute = new MapUploadedFile();\n        $argument = new ArgumentMetadata(\n            'qux',\n            UploadedFile::class,\n            false,\n            true,\n            'default-value',\n            false,\n            [$attribute::class => $attribute]\n        );\n        /** @var HttpKernelInterface&MockObject $httpKernel */\n        $httpKernel = $this->createStub(HttpKernelInterface::class);\n        $event = new ControllerArgumentsEvent(\n            $httpKernel,\n            static function () {},\n            $resolver->resolve($request, $argument),\n            $request,\n            HttpKernelInterface::MAIN_REQUEST\n        );\n        $resolver->onKernelControllerArguments($event);\n        $data = $event->getArguments()[0];\n\n        $this->assertSame('default-value', $data);\n    }\n\n    public static function provideContext(): iterable\n    {\n        $resolver = new RequestPayloadValueResolver(\n            new Serializer(),\n            (new ValidatorBuilder())->getValidator()\n        );\n        $small = new UploadedFile(\n            self::FIXTURES_BASE_PATH.'/file-small.txt',\n            'file-small.txt',\n            'text/plain',\n            null,\n            true\n        );\n        $big = new UploadedFile(\n            self::FIXTURES_BASE_PATH.'/file-big.txt',\n            'file-big.txt',\n            'text/plain',\n            null,\n            true\n        );\n        $request = Request::create(\n            '/',\n            'POST',\n            files: [\n                'foo' => $small,\n                'bar' => $big,\n                'baz' => [$small, $big],\n            ],\n            server: ['HTTP_CONTENT_TYPE' => 'multipart/form-data']\n        );\n\n        yield 'standard' => [$resolver, $request];\n    }\n}\n"
  },
  {
    "path": "Tests/Controller/ArgumentResolverTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Controller;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\DependencyInjection\\ServiceLocator;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Session\\Session;\nuse Symfony\\Component\\HttpFoundation\\Session\\SessionInterface;\nuse Symfony\\Component\\HttpFoundation\\Session\\Storage\\MockArraySessionStorage;\nuse Symfony\\Component\\HttpKernel\\Attribute\\ValueResolver;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\DefaultValueResolver;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\RequestAttributeValueResolver;\nuse Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadataFactory;\nuse Symfony\\Component\\HttpKernel\\Exception\\NearMissValueResolverException;\nuse Symfony\\Component\\HttpKernel\\Exception\\ResolverNotFoundException;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller\\ExtendingRequest;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller\\ExtendingSession;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller\\NullableController;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller\\VariadicController;\n\nclass ArgumentResolverTest extends TestCase\n{\n    public static function getResolver(array $chainableResolvers = [], ?array $namedResolvers = null): ArgumentResolver\n    {\n        if (null !== $namedResolvers) {\n            $namedResolvers = new ServiceLocator(array_map(static fn ($resolver) => static fn () => $resolver, $namedResolvers));\n        }\n\n        return new ArgumentResolver(new ArgumentMetadataFactory(), $chainableResolvers, $namedResolvers);\n    }\n\n    public function testDefaultState()\n    {\n        $this->assertEquals(self::getResolver(), new ArgumentResolver());\n        $this->assertNotEquals(self::getResolver(), new ArgumentResolver(null, [new RequestAttributeValueResolver()]));\n    }\n\n    public function testGetArguments()\n    {\n        $request = Request::create('/');\n        $request->attributes->set('foo', 'foo');\n        $controller = [new ArgumentResolverTestController(), 'controllerWithFoo'];\n\n        $this->assertEquals(['foo'], self::getResolver()->getArguments($request, $controller), '->getArguments() returns an array of arguments for the controller method');\n    }\n\n    public function testGetArgumentsReturnsEmptyArrayWhenNoArguments()\n    {\n        $request = Request::create('/');\n        $controller = [new ArgumentResolverTestController(), 'controllerWithoutArguments'];\n\n        $this->assertEquals([], self::getResolver()->getArguments($request, $controller), '->getArguments() returns an empty array if the method takes no arguments');\n    }\n\n    public function testGetArgumentsUsesDefaultValue()\n    {\n        $request = Request::create('/');\n        $request->attributes->set('foo', 'foo');\n        $controller = [new ArgumentResolverTestController(), 'controllerWithFooAndDefaultBar'];\n\n        $this->assertEquals(['foo', null], self::getResolver()->getArguments($request, $controller), '->getArguments() uses default values if present');\n    }\n\n    public function testGetArgumentsOverrideDefaultValueByRequestAttribute()\n    {\n        $request = Request::create('/');\n        $request->attributes->set('foo', 'foo');\n        $request->attributes->set('bar', 'bar');\n        $controller = [new ArgumentResolverTestController(), 'controllerWithFooAndDefaultBar'];\n\n        $this->assertEquals(['foo', 'bar'], self::getResolver()->getArguments($request, $controller), '->getArguments() overrides default values if provided in the request attributes');\n    }\n\n    public function testGetArgumentsFromClosure()\n    {\n        $request = Request::create('/');\n        $request->attributes->set('foo', 'foo');\n        $controller = static function ($foo) {};\n\n        $this->assertEquals(['foo'], self::getResolver()->getArguments($request, $controller));\n    }\n\n    public function testGetArgumentsUsesDefaultValueFromClosure()\n    {\n        $request = Request::create('/');\n        $request->attributes->set('foo', 'foo');\n        $controller = static function ($foo, $bar = 'bar') {};\n\n        $this->assertEquals(['foo', 'bar'], self::getResolver()->getArguments($request, $controller));\n    }\n\n    public function testGetArgumentsFromInvokableObject()\n    {\n        $request = Request::create('/');\n        $request->attributes->set('foo', 'foo');\n        $controller = new ArgumentResolverTestController();\n\n        $this->assertEquals(['foo', null], self::getResolver()->getArguments($request, $controller));\n\n        // Test default bar overridden by request attribute\n        $request->attributes->set('bar', 'bar');\n\n        $this->assertEquals(['foo', 'bar'], self::getResolver()->getArguments($request, $controller));\n    }\n\n    public function testGetArgumentsFromFunctionName()\n    {\n        $request = Request::create('/');\n        $request->attributes->set('foo', 'foo');\n        $request->attributes->set('foobar', 'foobar');\n        $controller = __NAMESPACE__.'\\controller_function';\n\n        $this->assertEquals(['foo', 'foobar'], self::getResolver()->getArguments($request, $controller));\n    }\n\n    public function testGetArgumentsFailsOnUnresolvedValue()\n    {\n        $request = Request::create('/');\n        $request->attributes->set('foo', 'foo');\n        $request->attributes->set('foobar', 'foobar');\n        $controller = [new ArgumentResolverTestController(), 'controllerWithFooBarFoobar'];\n\n        try {\n            self::getResolver()->getArguments($request, $controller);\n            $this->fail('->getArguments() throws a \\RuntimeException exception if it cannot determine the argument value');\n        } catch (\\Exception $e) {\n            $this->assertInstanceOf(\\RuntimeException::class, $e, '->getArguments() throws a \\RuntimeException exception if it cannot determine the argument value');\n        }\n    }\n\n    public function testGetArgumentsInjectsRequest()\n    {\n        $request = Request::create('/');\n        $controller = [new ArgumentResolverTestController(), 'controllerWithRequest'];\n\n        $this->assertEquals([$request], self::getResolver()->getArguments($request, $controller), '->getArguments() injects the request');\n    }\n\n    public function testGetArgumentsInjectsExtendingRequest()\n    {\n        $request = ExtendingRequest::create('/');\n        $controller = [new ArgumentResolverTestController(), 'controllerWithExtendingRequest'];\n\n        $this->assertEquals([$request], self::getResolver()->getArguments($request, $controller), '->getArguments() injects the request when extended');\n    }\n\n    public function testGetVariadicArguments()\n    {\n        $request = Request::create('/');\n        $request->attributes->set('foo', 'foo');\n        $request->attributes->set('bar', ['foo', 'bar']);\n        $controller = [new VariadicController(), 'action'];\n\n        $this->assertEquals(['foo', 'foo', 'bar'], self::getResolver()->getArguments($request, $controller));\n    }\n\n    public function testGetVariadicArgumentsWithoutArrayInRequest()\n    {\n        $this->expectException(\\InvalidArgumentException::class);\n        $request = Request::create('/');\n        $request->attributes->set('foo', 'foo');\n        $request->attributes->set('bar', 'foo');\n        $controller = [new VariadicController(), 'action'];\n\n        self::getResolver()->getArguments($request, $controller);\n    }\n\n    public function testIfExceptionIsThrownWhenMissingAnArgument()\n    {\n        $request = Request::create('/');\n        $controller = (new ArgumentResolverTestController())->controllerWithFoo(...);\n\n        $this->expectException(\\RuntimeException::class);\n        $this->expectExceptionMessage('Controller \"'.ArgumentResolverTestController::class.'::controllerWithFoo\" requires the \"$foo\" argument that could not be resolved. 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.');\n        self::getResolver()->getArguments($request, $controller);\n    }\n\n    public function testGetNullableArguments()\n    {\n        $request = Request::create('/');\n        $request->attributes->set('foo', 'foo');\n        $request->attributes->set('bar', new \\stdClass());\n        $request->attributes->set('last', 'last');\n        $controller = [new NullableController(), 'action'];\n\n        $this->assertEquals(['foo', new \\stdClass(), 'value', 'last'], self::getResolver()->getArguments($request, $controller));\n    }\n\n    public function testGetNullableArgumentsWithDefaults()\n    {\n        $request = Request::create('/');\n        $request->attributes->set('last', 'last');\n        $controller = [new NullableController(), 'action'];\n\n        $this->assertEquals([null, null, 'value', 'last'], self::getResolver()->getArguments($request, $controller));\n    }\n\n    public function testGetSessionArguments()\n    {\n        $session = new Session(new MockArraySessionStorage());\n        $request = Request::create('/');\n        $request->setSession($session);\n        $controller = (new ArgumentResolverTestController())->controllerWithSession(...);\n\n        $this->assertEquals([$session], self::getResolver()->getArguments($request, $controller));\n    }\n\n    public function testGetSessionArgumentsWithExtendedSession()\n    {\n        $session = new ExtendingSession(new MockArraySessionStorage());\n        $request = Request::create('/');\n        $request->setSession($session);\n        $controller = (new ArgumentResolverTestController())->controllerWithExtendingSession(...);\n\n        $this->assertEquals([$session], self::getResolver()->getArguments($request, $controller));\n    }\n\n    public function testGetSessionArgumentsWithInterface()\n    {\n        $session = new Session(new MockArraySessionStorage());\n        $request = Request::create('/');\n        $request->setSession($session);\n        $controller = (new ArgumentResolverTestController())->controllerWithSessionInterface(...);\n\n        $this->assertEquals([$session], self::getResolver()->getArguments($request, $controller));\n    }\n\n    public function testGetSessionMissMatchWithInterface()\n    {\n        $this->expectException(\\RuntimeException::class);\n        $session = new Session(new MockArraySessionStorage());\n        $request = Request::create('/');\n        $request->setSession($session);\n        $controller = (new ArgumentResolverTestController())->controllerWithExtendingSession(...);\n\n        self::getResolver()->getArguments($request, $controller);\n    }\n\n    public function testGetSessionMissMatchWithImplementation()\n    {\n        $this->expectException(\\RuntimeException::class);\n        $session = new Session(new MockArraySessionStorage());\n        $request = Request::create('/');\n        $request->setSession($session);\n        $controller = (new ArgumentResolverTestController())->controllerWithExtendingSession(...);\n\n        self::getResolver()->getArguments($request, $controller);\n    }\n\n    public function testGetSessionMissMatchOnNull()\n    {\n        $this->expectException(\\RuntimeException::class);\n        $request = Request::create('/');\n        $controller = (new ArgumentResolverTestController())->controllerWithExtendingSession(...);\n\n        self::getResolver()->getArguments($request, $controller);\n    }\n\n    public function testTargetedResolver()\n    {\n        $resolver = self::getResolver([], [DefaultValueResolver::class => new DefaultValueResolver()]);\n\n        $request = Request::create('/');\n        $request->attributes->set('foo', 'bar');\n        $controller = (new ArgumentResolverTestController())->controllerTargetingResolver(...);\n\n        $this->assertSame([1], $resolver->getArguments($request, $controller));\n    }\n\n    public function testTargetedResolverWithDefaultValue()\n    {\n        $resolver = self::getResolver([], [TestEntityValueResolver::class => new TestEntityValueResolver()]);\n\n        $request = Request::create('/');\n        $controller = (new ArgumentResolverTestController())->controllerTargetingResolverWithDefaultValue(...);\n\n        /** @var Post[] $arguments */\n        $arguments = $resolver->getArguments($request, $controller);\n\n        $this->assertCount(1, $arguments);\n        $this->assertSame('Default', $arguments[0]->title);\n    }\n\n    public function testTargetedResolverWithNullableValue()\n    {\n        $resolver = self::getResolver([], [TestEntityValueResolver::class => new TestEntityValueResolver()]);\n\n        $request = Request::create('/');\n        $controller = (new ArgumentResolverTestController())->controllerTargetingResolverWithNullableValue(...);\n\n        $this->assertSame([null], $resolver->getArguments($request, $controller));\n    }\n\n    public function testTargetedResolverWithRequestAttributeValue()\n    {\n        $resolver = self::getResolver([], [TestEntityValueResolver::class => new TestEntityValueResolver()]);\n\n        $request = Request::create('/');\n        $request->attributes->set('foo', $object = new Post('Random '.time()));\n        $controller = (new ArgumentResolverTestController())->controllerTargetingResolverWithTestEntity(...);\n\n        $this->assertSame([$object], $resolver->getArguments($request, $controller));\n    }\n\n    public function testDisabledResolver()\n    {\n        $resolver = self::getResolver(namedResolvers: []);\n\n        $request = Request::create('/');\n        $request->attributes->set('foo', 'bar');\n        $controller = (new ArgumentResolverTestController())->controllerDisablingResolver(...);\n\n        $this->assertSame([1], $resolver->getArguments($request, $controller));\n    }\n\n    public function testManyTargetedResolvers()\n    {\n        $resolver = self::getResolver(namedResolvers: []);\n\n        $request = Request::create('/');\n        $controller = (new ArgumentResolverTestController())->controllerTargetingManyResolvers(...);\n\n        $this->expectException(\\LogicException::class);\n        $resolver->getArguments($request, $controller);\n    }\n\n    public function testUnknownTargetedResolver()\n    {\n        $resolver = self::getResolver(namedResolvers: []);\n\n        $request = Request::create('/');\n        $controller = (new ArgumentResolverTestController())->controllerTargetingUnknownResolver(...);\n\n        $this->expectException(ResolverNotFoundException::class);\n        $resolver->getArguments($request, $controller);\n    }\n\n    public function testResolversChainCompletionWhenResolverThrowsSpecialException()\n    {\n        $failingValueResolver = new class implements ValueResolverInterface {\n            public function resolve(Request $request, ArgumentMetadata $argument): iterable\n            {\n                throw new NearMissValueResolverException('This resolver throws an exception');\n            }\n        };\n        // Put failing value resolver in the beginning\n        $expectedToCallValueResolver = $this->createMock(ValueResolverInterface::class);\n        $expectedToCallValueResolver->expects($this->once())->method('resolve')->willReturn([123]);\n\n        $resolver = self::getResolver([$failingValueResolver, ...ArgumentResolver::getDefaultArgumentValueResolvers(), $expectedToCallValueResolver]);\n        $request = Request::create('/');\n        $controller = [new ArgumentResolverTestController(), 'controllerWithFoo'];\n\n        $actualArguments = $resolver->getArguments($request, $controller);\n        self::assertEquals([123], $actualArguments);\n    }\n\n    public function testExceptionListSingle()\n    {\n        $failingValueResolverOne = new class implements ValueResolverInterface {\n            public function resolve(Request $request, ArgumentMetadata $argument): iterable\n            {\n                throw new NearMissValueResolverException('Some reason why value could not be resolved.');\n            }\n        };\n\n        $resolver = self::getResolver([$failingValueResolverOne]);\n        $request = Request::create('/');\n        $controller = [new ArgumentResolverTestController(), 'controllerWithFoo'];\n\n        $this->expectException(\\RuntimeException::class);\n        $this->expectExceptionMessage('Controller \"Symfony\\Component\\HttpKernel\\Tests\\Controller\\ArgumentResolverTestController::controllerWithFoo\" requires the \"$foo\" argument that could not be resolved. Some reason why value could not be resolved.');\n        $resolver->getArguments($request, $controller);\n    }\n\n    public function testExceptionListMultiple()\n    {\n        $failingValueResolverOne = new class implements ValueResolverInterface {\n            public function resolve(Request $request, ArgumentMetadata $argument): iterable\n            {\n                throw new NearMissValueResolverException('Some reason why value could not be resolved.');\n            }\n        };\n        $failingValueResolverTwo = new class implements ValueResolverInterface {\n            public function resolve(Request $request, ArgumentMetadata $argument): iterable\n            {\n                throw new NearMissValueResolverException('Another reason why value could not be resolved.');\n            }\n        };\n\n        $resolver = self::getResolver([$failingValueResolverOne, $failingValueResolverTwo]);\n        $request = Request::create('/');\n        $controller = [new ArgumentResolverTestController(), 'controllerWithFoo'];\n\n        $this->expectException(\\RuntimeException::class);\n        $this->expectExceptionMessage('Controller \"Symfony\\Component\\HttpKernel\\Tests\\Controller\\ArgumentResolverTestController::controllerWithFoo\" requires the \"$foo\" argument that could not be resolved. Possible reasons: 1) Some reason why value could not be resolved. 2) Another reason why value could not be resolved.');\n        $resolver->getArguments($request, $controller);\n    }\n}\n\nclass ArgumentResolverTestController\n{\n    public function __invoke($foo, $bar = null)\n    {\n    }\n\n    public function controllerWithFoo($foo)\n    {\n    }\n\n    public function controllerWithoutArguments()\n    {\n    }\n\n    public function controllerWithFooAndDefaultBar($foo, $bar = null)\n    {\n    }\n\n    public function controllerWithFooBarFoobar($foo, $bar, $foobar)\n    {\n    }\n\n    public function controllerWithRequest(Request $request)\n    {\n    }\n\n    public function controllerWithExtendingRequest(ExtendingRequest $request)\n    {\n    }\n\n    public function controllerWithSession(Session $session)\n    {\n    }\n\n    public function controllerWithSessionInterface(SessionInterface $session)\n    {\n    }\n\n    public function controllerWithExtendingSession(ExtendingSession $session)\n    {\n    }\n\n    public function controllerTargetingResolver(#[ValueResolver(DefaultValueResolver::class)] int $foo = 1)\n    {\n    }\n\n    public function controllerTargetingResolverWithDefaultValue(#[ValueResolver(TestEntityValueResolver::class)] Post $foo = new Post('Default'))\n    {\n    }\n\n    public function controllerTargetingResolverWithNullableValue(#[ValueResolver(TestEntityValueResolver::class)] ?Post $foo)\n    {\n    }\n\n    public function controllerTargetingResolverWithTestEntity(#[ValueResolver(TestEntityValueResolver::class)] Post $foo)\n    {\n    }\n\n    public function controllerDisablingResolver(#[ValueResolver(RequestAttributeValueResolver::class, disabled: true)] int $foo = 1)\n    {\n    }\n\n    public function controllerTargetingManyResolvers(\n        #[ValueResolver(RequestAttributeValueResolver::class)]\n        #[ValueResolver(DefaultValueResolver::class)]\n        int $foo,\n    ) {\n    }\n\n    public function controllerTargetingUnknownResolver(\n        #[ValueResolver('foo')]\n        int $bar,\n    ) {\n    }\n}\n\nfunction controller_function($foo, $foobar)\n{\n}\n\nclass TestEntityValueResolver implements ValueResolverInterface\n{\n    public function resolve(Request $request, ArgumentMetadata $argument): iterable\n    {\n        return Post::class === $argument->getType() && $request->request->has('title')\n            ? [new Post($request->request->get('title'))]\n            : [];\n    }\n}\n\nclass Post\n{\n    public function __construct(\n        public readonly string $title,\n    ) {\n    }\n}\n"
  },
  {
    "path": "Tests/Controller/ContainerControllerResolverTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Controller;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\DependencyInjection\\Container;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ContainerControllerResolver;\n\nclass ContainerControllerResolverTest extends ControllerResolverTest\n{\n    public function testGetControllerService()\n    {\n        $service = new ControllerTestService('foo');\n\n        $container = new Container();\n        $container->set('foo', $service);\n\n        $resolver = $this->createControllerResolver(null, $container);\n        $request = Request::create('/');\n        $request->attributes->set('_controller', 'foo::action');\n\n        $controller = $resolver->getController($request);\n\n        $this->assertSame($service, $controller[0]);\n        $this->assertSame('action', $controller[1]);\n    }\n\n    public function testGetControllerInvokableService()\n    {\n        $service = new InvokableControllerService('bar');\n\n        $container = new Container();\n        $container->set('foo', $service);\n\n        $resolver = $this->createControllerResolver(null, $container);\n        $request = Request::create('/');\n        $request->attributes->set('_controller', 'foo');\n\n        $controller = $resolver->getController($request);\n\n        $this->assertSame($service, $controller);\n    }\n\n    public function testGetControllerInvokableServiceWithClassNameAsName()\n    {\n        $service = new InvokableControllerService('bar');\n\n        $container = new Container();\n        $container->set(InvokableControllerService::class, $service);\n\n        $resolver = $this->createControllerResolver(null, $container);\n        $request = Request::create('/');\n        $request->attributes->set('_controller', InvokableControllerService::class);\n\n        $controller = $resolver->getController($request);\n\n        $this->assertSame($service, $controller);\n    }\n\n    #[DataProvider('getControllers')]\n    public function testInstantiateControllerWhenControllerStartsWithABackslash($controller)\n    {\n        $service = new ControllerTestService('foo');\n        $class = ControllerTestService::class;\n\n        $container = new Container();\n        $container->set($class, $service);\n\n        $resolver = $this->createControllerResolver(null, $container);\n        $request = Request::create('/');\n        $request->attributes->set('_controller', $controller);\n\n        $controller = $resolver->getController($request);\n\n        $this->assertInstanceOf(ControllerTestService::class, $controller[0]);\n        $this->assertSame('action', $controller[1]);\n    }\n\n    public static function getControllers()\n    {\n        return [\n            ['\\\\'.ControllerTestService::class.'::action'],\n        ];\n    }\n\n    public function testExceptionWhenUsingRemovedControllerServiceWithClassNameAsName()\n    {\n        $this->expectException(\\InvalidArgumentException::class);\n        $this->expectExceptionMessage('Controller \"Symfony\\Component\\HttpKernel\\Tests\\Controller\\ControllerTestService\" cannot be fetched from the container because it is private. Did you forget to tag the service with \"controller.service_arguments\"?');\n        $container = $this->createMock(Container::class);\n        $container->expects($this->once())\n            ->method('has')\n            ->with(ControllerTestService::class)\n            ->willReturn(false)\n        ;\n\n        $container->expects($this->atLeastOnce())\n            ->method('getRemovedIds')\n            ->with()\n            ->willReturn([ControllerTestService::class => true])\n        ;\n\n        $resolver = $this->createControllerResolver(null, $container);\n        $request = Request::create('/');\n        $request->attributes->set('_controller', [ControllerTestService::class, 'action']);\n\n        $resolver->getController($request);\n    }\n\n    public function testExceptionWhenUsingRemovedControllerService()\n    {\n        $this->expectException(\\InvalidArgumentException::class);\n        $this->expectExceptionMessage('Controller \"app.my_controller\" cannot be fetched from the container because it is private. Did you forget to tag the service with \"controller.service_arguments\"?');\n        $container = $this->createMock(Container::class);\n        $container->expects($this->once())\n            ->method('has')\n            ->with('app.my_controller')\n            ->willReturn(false)\n        ;\n\n        $container->expects($this->atLeastOnce())\n            ->method('getRemovedIds')\n            ->with()\n            ->willReturn(['app.my_controller' => true])\n        ;\n\n        $resolver = $this->createControllerResolver(null, $container);\n\n        $request = Request::create('/');\n        $request->attributes->set('_controller', 'app.my_controller');\n        $resolver->getController($request);\n    }\n\n    public static function getUndefinedControllers(): array\n    {\n        $tests = parent::getUndefinedControllers();\n        $tests[0] = ['foo', \\InvalidArgumentException::class, 'Controller \"foo\" does neither exist as service nor as class'];\n        $tests[1] = ['oof::bar', \\InvalidArgumentException::class, 'Controller \"oof\" does neither exist as service nor as class'];\n        $tests[2] = [['oof', 'bar'], \\InvalidArgumentException::class, 'Controller \"oof\" does neither exist as service nor as class'];\n        $tests[] = [\n            [ControllerTestService::class, 'action'],\n            \\InvalidArgumentException::class,\n            'Controller \"Symfony\\Component\\HttpKernel\\Tests\\Controller\\ControllerTestService\" has required constructor arguments and does not exist in the container. Did you forget to define the controller as a service?',\n        ];\n        $tests[] = [\n            ControllerTestService::class.'::action',\n            \\InvalidArgumentException::class, 'Controller \"Symfony\\Component\\HttpKernel\\Tests\\Controller\\ControllerTestService\" has required constructor arguments and does not exist in the container. Did you forget to define the controller as a service?',\n        ];\n        $tests[] = [\n            InvokableControllerService::class,\n            \\InvalidArgumentException::class,\n            'Controller \"Symfony\\Component\\HttpKernel\\Tests\\Controller\\InvokableControllerService\" has required constructor arguments and does not exist in the container. Did you forget to define the controller as a service?',\n        ];\n\n        return $tests;\n    }\n\n    protected function createControllerResolver(?LoggerInterface $logger = null, ?ContainerInterface $container = null)\n    {\n        if (!$container) {\n            $container = new Container();\n        }\n\n        return new ContainerControllerResolver($container, $logger);\n    }\n}\n\nclass InvokableControllerService\n{\n    public function __construct($bar) // mandatory argument to prevent automatic instantiation\n    {\n    }\n\n    public function __invoke()\n    {\n    }\n}\n\nclass ControllerTestService\n{\n    public function __construct($foo)\n    {\n    }\n\n    public function action()\n    {\n    }\n}\n"
  },
  {
    "path": "Tests/Controller/ControllerResolverTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Controller;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\HttpFoundation\\Exception\\BadRequestException;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Attribute\\AsController;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerResolver;\n\nclass ControllerResolverTest extends TestCase\n{\n    public function testGetControllerWithoutControllerParameter()\n    {\n        $logger = $this->createMock(LoggerInterface::class);\n        $logger->expects($this->once())->method('warning')->with('Unable to look for the controller as the \"_controller\" parameter is missing.');\n        $resolver = $this->createControllerResolver($logger);\n\n        $request = Request::create('/');\n        $this->assertFalse($resolver->getController($request), '->getController() returns false when the request has no _controller attribute');\n    }\n\n    public function testGetControllerWithLambda()\n    {\n        $resolver = $this->createControllerResolver();\n\n        $request = Request::create('/');\n        $request->attributes->set('_controller', $lambda = static function () {});\n        $controller = $resolver->getController($request);\n        $this->assertSame($lambda, $controller);\n    }\n\n    public function testGetControllerWithObjectAndInvokeMethod()\n    {\n        $resolver = $this->createControllerResolver();\n        $object = new InvokableController();\n\n        $request = Request::create('/');\n        $request->attributes->set('_controller', $object);\n        $controller = $resolver->getController($request);\n        $this->assertSame($object, $controller);\n    }\n\n    public function testGetControllerWithObjectAndMethod()\n    {\n        $resolver = $this->createControllerResolver();\n        $object = new ControllerTest();\n\n        $request = Request::create('/');\n        $request->attributes->set('_controller', [$object, 'publicAction']);\n        $controller = $resolver->getController($request);\n        $this->assertSame([$object, 'publicAction'], $controller);\n    }\n\n    public function testGetControllerWithClassAndMethodAsArray()\n    {\n        $resolver = $this->createControllerResolver();\n\n        $request = Request::create('/');\n        $request->attributes->set('_controller', [ControllerTest::class, 'publicAction']);\n        $controller = $resolver->getController($request);\n        $this->assertInstanceOf(ControllerTest::class, $controller[0]);\n        $this->assertSame('publicAction', $controller[1]);\n    }\n\n    public function testGetControllerWithClassAndMethodAsString()\n    {\n        $resolver = $this->createControllerResolver();\n\n        $request = Request::create('/');\n        $request->attributes->set('_controller', ControllerTest::class.'::publicAction');\n        $controller = $resolver->getController($request);\n        $this->assertInstanceOf(ControllerTest::class, $controller[0]);\n        $this->assertSame('publicAction', $controller[1]);\n    }\n\n    public function testGetControllerWithInvokableClass()\n    {\n        $resolver = $this->createControllerResolver();\n\n        $request = Request::create('/');\n        $request->attributes->set('_controller', InvokableController::class);\n        $controller = $resolver->getController($request);\n        $this->assertInstanceOf(InvokableController::class, $controller);\n    }\n\n    public function testGetControllerOnObjectWithoutInvokeMethod()\n    {\n        $this->expectException(\\InvalidArgumentException::class);\n        $resolver = $this->createControllerResolver();\n\n        $request = Request::create('/');\n        $request->attributes->set('_controller', new \\stdClass());\n        $resolver->getController($request);\n    }\n\n    public function testGetControllerWithFunction()\n    {\n        $resolver = $this->createControllerResolver();\n\n        $request = Request::create('/');\n        $request->attributes->set('_controller', 'Symfony\\Component\\HttpKernel\\Tests\\Controller\\some_controller_function');\n        $controller = $resolver->getController($request);\n        $this->assertSame('Symfony\\Component\\HttpKernel\\Tests\\Controller\\some_controller_function', $controller);\n    }\n\n    public function testGetControllerWithClosure()\n    {\n        $resolver = $this->createControllerResolver();\n\n        $closure = static fn () => 'test';\n\n        $request = Request::create('/');\n        $request->attributes->set('_controller', $closure);\n        $controller = $resolver->getController($request);\n        $this->assertInstanceOf(\\Closure::class, $controller);\n        $this->assertSame('test', $controller());\n    }\n\n    #[DataProvider('getStaticControllers')]\n    public function testGetControllerWithStaticController($staticController, $returnValue)\n    {\n        $resolver = $this->createControllerResolver();\n\n        $request = Request::create('/');\n        $request->attributes->set('_controller', $staticController);\n        $controller = $resolver->getController($request);\n        $this->assertSame($staticController, $controller);\n        $this->assertSame($returnValue, $controller());\n    }\n\n    public static function getStaticControllers()\n    {\n        return [\n            [TestAbstractController::class.'::staticAction', 'foo'],\n            [[TestAbstractController::class, 'staticAction'], 'foo'],\n            [PrivateConstructorController::class.'::staticAction', 'bar'],\n            [[PrivateConstructorController::class, 'staticAction'], 'bar'],\n        ];\n    }\n\n    #[DataProvider('getUndefinedControllers')]\n    public function testGetControllerWithUndefinedController($controller, $exceptionName = null, $exceptionMessage = null)\n    {\n        $resolver = $this->createControllerResolver();\n        $this->expectException($exceptionName);\n        $this->expectExceptionMessage($exceptionMessage);\n\n        $request = Request::create('/');\n        $request->attributes->set('_controller', $controller);\n        $resolver->getController($request);\n    }\n\n    public static function getUndefinedControllers()\n    {\n        $controller = new ControllerTest();\n\n        return [\n            ['foo', \\Error::class, 'Class \"foo\" not found'],\n            ['oof::bar', \\Error::class, 'Class \"oof\" not found'],\n            [['oof', 'bar'], \\Error::class, 'Class \"oof\" not found'],\n            ['Symfony\\Component\\HttpKernel\\Tests\\Controller\\ControllerTest::staticsAction', \\InvalidArgumentException::class, 'The controller for URI \"/\" is not callable: Expected method \"staticsAction\" on class \"Symfony\\Component\\HttpKernel\\Tests\\Controller\\ControllerTest\", did you mean \"staticAction\"?'],\n            ['Symfony\\Component\\HttpKernel\\Tests\\Controller\\ControllerTest::privateAction', \\InvalidArgumentException::class, 'The controller for URI \"/\" is not callable: Method \"privateAction\" on class \"Symfony\\Component\\HttpKernel\\Tests\\Controller\\ControllerTest\" should be public and non-abstract'],\n            ['Symfony\\Component\\HttpKernel\\Tests\\Controller\\ControllerTest::protectedAction', \\InvalidArgumentException::class, 'The controller for URI \"/\" is not callable: Method \"protectedAction\" on class \"Symfony\\Component\\HttpKernel\\Tests\\Controller\\ControllerTest\" should be public and non-abstract'],\n            ['Symfony\\Component\\HttpKernel\\Tests\\Controller\\ControllerTest::undefinedAction', \\InvalidArgumentException::class, 'The controller for URI \"/\" is not callable: Expected method \"undefinedAction\" on class \"Symfony\\Component\\HttpKernel\\Tests\\Controller\\ControllerTest\". Available methods: \"publicAction\", \"staticAction\"'],\n            ['Symfony\\Component\\HttpKernel\\Tests\\Controller\\ControllerTest', \\InvalidArgumentException::class, 'The controller for URI \"/\" is not callable: Controller class \"Symfony\\Component\\HttpKernel\\Tests\\Controller\\ControllerTest\" cannot be called without a method name. You need to implement \"__invoke\" or use one of the available methods: \"publicAction\", \"staticAction\".'],\n            [[$controller, 'staticsAction'], \\InvalidArgumentException::class, 'The controller for URI \"/\" is not callable: Expected method \"staticsAction\" on class \"Symfony\\Component\\HttpKernel\\Tests\\Controller\\ControllerTest\", did you mean \"staticAction\"?'],\n            [[$controller, 'privateAction'], \\InvalidArgumentException::class, 'The controller for URI \"/\" is not callable: Method \"privateAction\" on class \"Symfony\\Component\\HttpKernel\\Tests\\Controller\\ControllerTest\" should be public and non-abstract'],\n            [[$controller, 'protectedAction'], \\InvalidArgumentException::class, 'The controller for URI \"/\" is not callable: Method \"protectedAction\" on class \"Symfony\\Component\\HttpKernel\\Tests\\Controller\\ControllerTest\" should be public and non-abstract'],\n            [[$controller, 'undefinedAction'], \\InvalidArgumentException::class, 'The controller for URI \"/\" is not callable: Expected method \"undefinedAction\" on class \"Symfony\\Component\\HttpKernel\\Tests\\Controller\\ControllerTest\". Available methods: \"publicAction\", \"staticAction\"'],\n            [$controller, \\InvalidArgumentException::class, 'The controller for URI \"/\" is not callable: Controller class \"Symfony\\Component\\HttpKernel\\Tests\\Controller\\ControllerTest\" cannot be called without a method name. You need to implement \"__invoke\" or use one of the available methods: \"publicAction\", \"staticAction\".'],\n            [['a' => 'foo', 'b' => 'bar'], \\InvalidArgumentException::class, 'The controller for URI \"/\" is not callable: Invalid array callable, expected [controller, method].'],\n        ];\n    }\n\n    public function testAllowedControllerTypes()\n    {\n        $resolver = $this->createControllerResolver();\n\n        $request = Request::create('/');\n        $controller = new ControllerTest();\n        $request->attributes->set('_controller', [$controller, 'publicAction']);\n        $request->attributes->set('_check_controller_is_allowed', true);\n\n        try {\n            $resolver->getController($request);\n            $this->expectException(BadRequestException::class);\n        } catch (BadRequestException) {\n            // expected\n        }\n\n        $resolver->allowControllers(types: [ControllerTest::class]);\n\n        $this->assertSame([$controller, 'publicAction'], $resolver->getController($request));\n\n        $request->attributes->set('_controller', $action = $controller->publicAction(...));\n        $this->assertSame($action, $resolver->getController($request));\n    }\n\n    public function testAllowedControllerAttributes()\n    {\n        $resolver = $this->createControllerResolver();\n\n        $request = Request::create('/');\n        $controller = some_controller_function(...);\n        $request->attributes->set('_controller', $controller);\n        $request->attributes->set('_check_controller_is_allowed', true);\n\n        try {\n            $resolver->getController($request);\n            $this->expectException(BadRequestException::class);\n        } catch (BadRequestException) {\n            // expected\n        }\n\n        $resolver->allowControllers(attributes: [DummyController::class]);\n\n        $this->assertSame($controller, $resolver->getController($request));\n\n        $controller = some_controller_function::class;\n        $request->attributes->set('_controller', $controller);\n        $this->assertSame($controller, $resolver->getController($request));\n    }\n\n    public function testAllowedAsControllerAttribute()\n    {\n        $resolver = $this->createControllerResolver();\n\n        $request = Request::create('/');\n        $controller = new InvokableController();\n        $request->attributes->set('_controller', [$controller, '__invoke']);\n        $request->attributes->set('_check_controller_is_allowed', true);\n\n        $this->assertSame([$controller, '__invoke'], $resolver->getController($request));\n\n        $request->attributes->set('_controller', $controller);\n        $this->assertSame($controller, $resolver->getController($request));\n    }\n\n    protected function createControllerResolver(?LoggerInterface $logger = null)\n    {\n        return new ControllerResolver($logger);\n    }\n}\n\n#[DummyController]\nfunction some_controller_function($foo, $foobar)\n{\n}\n\nclass ControllerTest\n{\n    public function __construct()\n    {\n    }\n\n    public function __toString(): string\n    {\n        return '';\n    }\n\n    public function publicAction()\n    {\n    }\n\n    private function privateAction()\n    {\n    }\n\n    protected function protectedAction()\n    {\n    }\n\n    public static function staticAction()\n    {\n    }\n}\n\n#[AsController]\nclass InvokableController\n{\n    public function __invoke($foo, $bar = null)\n    {\n    }\n}\n\nabstract class TestAbstractController\n{\n    public static function staticAction()\n    {\n        return 'foo';\n    }\n}\n\nclass PrivateConstructorController\n{\n    private function __construct()\n    {\n    }\n\n    public static function staticAction()\n    {\n        return 'bar';\n    }\n}\n"
  },
  {
    "path": "Tests/Controller/ErrorControllerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Controller;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\ErrorHandler\\ErrorRenderer\\HtmlErrorRenderer;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Controller\\ErrorController;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\n\nclass ErrorControllerTest extends TestCase\n{\n    #[DataProvider('getInvokeControllerDataProvider')]\n    public function testInvokeController(Request $request, \\Exception $exception, int $statusCode, string $content)\n    {\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $errorRenderer = new HtmlErrorRenderer();\n        $controller = new ErrorController($kernel, null, $errorRenderer);\n        $response = $controller($exception);\n\n        $this->assertSame($statusCode, $response->getStatusCode());\n        self::assertStringContainsString($content, strtr($response->getContent(), [\"\\n\" => '', '    ' => '']));\n    }\n\n    public static function getInvokeControllerDataProvider()\n    {\n        yield 'default status code and HTML format' => [\n            new Request(),\n            new \\Exception(),\n            500,\n            'The server returned a \"500 Internal Server Error\".',\n        ];\n\n        yield 'custom status code' => [\n            new Request(),\n            new NotFoundHttpException('Page not found.'),\n            404,\n            'The server returned a \"404 Not Found\".',\n        ];\n\n        $request = new Request();\n        $request->attributes->set('_format', 'unknown');\n        yield 'default HTML format for unknown formats' => [\n            $request,\n            new HttpException(405, 'Invalid request.'),\n            405,\n            'The server returned a \"405 Method Not Allowed\".',\n        ];\n    }\n\n    public function testPreviewController()\n    {\n        $_controller = 'error_controller';\n        $code = 404;\n\n        $kernel = $this->createMock(HttpKernelInterface::class);\n        $kernel\n            ->expects($this->once())\n            ->method('handle')\n            ->with(\n                $this->callback(function (Request $request) use ($_controller, $code) {\n                    $exception = $request->attributes->get('exception');\n\n                    $this->assertSame($_controller, $request->attributes->get('_controller'));\n                    $this->assertInstanceOf(\\Throwable::class, $exception);\n                    $this->assertSame($code, $exception->getStatusCode());\n                    $this->assertFalse($request->attributes->get('showException'));\n\n                    return true;\n                }),\n                $this->equalTo(HttpKernelInterface::SUB_REQUEST)\n            )\n            ->willReturn($response = new Response());\n\n        $controller = new ErrorController($kernel, $_controller, new HtmlErrorRenderer());\n\n        $this->assertSame($response, $controller->preview(new Request(), $code));\n    }\n}\n"
  },
  {
    "path": "Tests/Controller/TraceableArgumentResolverTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Controller;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolverInterface;\nuse Symfony\\Component\\HttpKernel\\Controller\\TraceableArgumentResolver;\nuse Symfony\\Component\\Stopwatch\\Stopwatch;\nuse Symfony\\Component\\Stopwatch\\StopwatchEvent;\n\nclass TraceableArgumentResolverTest extends TestCase\n{\n    public function testStopwatchEventIsStoppedWhenResolverThrows()\n    {\n        $stopwatchEvent = $this->createMock(StopwatchEvent::class);\n        $stopwatchEvent->expects(self::once())->method('stop');\n\n        $stopwatch = $this->createStub(Stopwatch::class);\n        $stopwatch->method('start')->willReturn($stopwatchEvent);\n\n        $resolver = new class implements ArgumentResolverInterface {\n            public function getArguments(Request $request, callable $controller, ?\\ReflectionFunctionAbstract $reflector = null): array\n            {\n                throw new \\Exception();\n            }\n        };\n\n        $traceableResolver = new TraceableArgumentResolver($resolver, $stopwatch);\n\n        try {\n            $traceableResolver->getArguments(new Request(), static function () {});\n        } catch (\\Exception $ex) {\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/Controller/TraceableControllerResolverTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Controller;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface;\nuse Symfony\\Component\\HttpKernel\\Controller\\TraceableControllerResolver;\nuse Symfony\\Component\\Stopwatch\\Stopwatch;\nuse Symfony\\Component\\Stopwatch\\StopwatchEvent;\n\nclass TraceableControllerResolverTest extends TestCase\n{\n    public function testStopwatchEventIsStoppedWhenResolverThrows()\n    {\n        $stopwatchEvent = $this->createMock(StopwatchEvent::class);\n        $stopwatchEvent->expects(self::once())->method('stop');\n\n        $stopwatch = $this->createStub(Stopwatch::class);\n        $stopwatch->method('start')->willReturn($stopwatchEvent);\n\n        $resolver = new class implements ControllerResolverInterface {\n            public function getController(Request $request): callable|false\n            {\n                throw new \\Exception();\n            }\n        };\n\n        $traceableResolver = new TraceableControllerResolver($resolver, $stopwatch);\n        try {\n            $traceableResolver->getController(new Request());\n        } catch (\\Exception $ex) {\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/ControllerMetadata/ArgumentMetadataFactoryTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\ControllerMetadata;\n\nuse Fake\\ImportedAndFake;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadataFactory;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute\\Foo;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller\\AttributeController;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller\\BasicTypesController;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller\\NullableController;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller\\VariadicController;\n\nclass ArgumentMetadataFactoryTest extends TestCase\n{\n    private ArgumentMetadataFactory $factory;\n\n    protected function setUp(): void\n    {\n        $this->factory = new ArgumentMetadataFactory();\n    }\n\n    public function testSignature1()\n    {\n        $arguments = $this->factory->createArgumentMetadata([$this, 'signature1']);\n\n        $this->assertEquals([\n            new ArgumentMetadata('foo', self::class, false, false, null, controllerName: $this::class.'::signature1'),\n            new ArgumentMetadata('bar', 'array', false, false, null, controllerName: $this::class.'::signature1'),\n            new ArgumentMetadata('baz', 'callable', false, false, null, controllerName: $this::class.'::signature1'),\n        ], $arguments);\n    }\n\n    public function testSignature2()\n    {\n        $arguments = $this->factory->createArgumentMetadata($this->signature2(...));\n\n        $this->assertEquals([\n            new ArgumentMetadata('foo', self::class, false, true, null, true, controllerName: $this::class.'::signature2'),\n            new ArgumentMetadata('bar', FakeClassThatDoesNotExist::class, false, true, null, true, controllerName: $this::class.'::signature2'),\n            new ArgumentMetadata('baz', 'Fake\\ImportedAndFake', false, true, null, true, controllerName: $this::class.'::signature2'),\n        ], $arguments);\n    }\n\n    public function testSignature3()\n    {\n        $arguments = $this->factory->createArgumentMetadata($this->signature3(...));\n\n        $this->assertEquals([\n            new ArgumentMetadata('bar', FakeClassThatDoesNotExist::class, false, false, null, controllerName: $this::class.'::signature3'),\n            new ArgumentMetadata('baz', 'Fake\\ImportedAndFake', false, false, null, controllerName: $this::class.'::signature3'),\n        ], $arguments);\n    }\n\n    public function testSignature4()\n    {\n        $arguments = $this->factory->createArgumentMetadata($this->signature4(...));\n\n        $this->assertEquals([\n            new ArgumentMetadata('foo', null, false, true, 'default', controllerName: $this::class.'::signature4'),\n            new ArgumentMetadata('bar', null, false, true, 500, controllerName: $this::class.'::signature4'),\n            new ArgumentMetadata('baz', null, false, true, [], controllerName: $this::class.'::signature4'),\n        ], $arguments);\n    }\n\n    public function testSignature5()\n    {\n        $arguments = $this->factory->createArgumentMetadata($this->signature5(...));\n\n        $this->assertEquals([\n            new ArgumentMetadata('foo', 'array', false, true, null, true, controllerName: $this::class.'::signature5'),\n            new ArgumentMetadata('bar', null, false, true, null, true, controllerName: $this::class.'::signature5'),\n        ], $arguments);\n    }\n\n    public function testVariadicSignature()\n    {\n        $arguments = $this->factory->createArgumentMetadata([new VariadicController(), 'action']);\n\n        $this->assertEquals([\n            new ArgumentMetadata('foo', null, false, false, null, controllerName: VariadicController::class.'::action'),\n            new ArgumentMetadata('bar', null, true, false, null, controllerName: VariadicController::class.'::action'),\n        ], $arguments);\n    }\n\n    public function testBasicTypesSignature()\n    {\n        $arguments = $this->factory->createArgumentMetadata([new BasicTypesController(), 'action']);\n\n        $this->assertEquals([\n            new ArgumentMetadata('foo', 'string', false, false, null, controllerName: BasicTypesController::class.'::action'),\n            new ArgumentMetadata('bar', 'int', false, false, null, controllerName: BasicTypesController::class.'::action'),\n            new ArgumentMetadata('baz', 'float', false, false, null, controllerName: BasicTypesController::class.'::action'),\n        ], $arguments);\n    }\n\n    public function testNamedClosure()\n    {\n        $arguments = $this->factory->createArgumentMetadata($this->signature1(...));\n\n        $this->assertEquals([\n            new ArgumentMetadata('foo', self::class, false, false, null, controllerName: $this::class.'::signature1'),\n            new ArgumentMetadata('bar', 'array', false, false, null, controllerName: $this::class.'::signature1'),\n            new ArgumentMetadata('baz', 'callable', false, false, null, controllerName: $this::class.'::signature1'),\n        ], $arguments);\n    }\n\n    public function testNullableTypesSignature()\n    {\n        $arguments = $this->factory->createArgumentMetadata([new NullableController(), 'action']);\n\n        $this->assertEquals([\n            new ArgumentMetadata('foo', 'string', false, false, null, true, controllerName: NullableController::class.'::action'),\n            new ArgumentMetadata('bar', \\stdClass::class, false, false, null, true, controllerName: NullableController::class.'::action'),\n            new ArgumentMetadata('baz', 'string', false, true, 'value', true, controllerName: NullableController::class.'::action'),\n            new ArgumentMetadata('last', 'string', false, true, '', false, controllerName: NullableController::class.'::action'),\n        ], $arguments);\n    }\n\n    public function testAttributeSignature()\n    {\n        $arguments = $this->factory->createArgumentMetadata([new AttributeController(), 'action']);\n\n        $this->assertEquals([\n            new ArgumentMetadata('baz', 'string', false, false, null, false, [new Foo('bar')], controllerName: AttributeController::class.'::action'),\n        ], $arguments);\n    }\n\n    public function testMultipleAttributes()\n    {\n        $this->factory->createArgumentMetadata([new AttributeController(), 'multiAttributeArg']);\n        $this->assertCount(1, $this->factory->createArgumentMetadata([new AttributeController(), 'multiAttributeArg'])[0]->getAttributes());\n    }\n\n    public function testIssue41478()\n    {\n        $arguments = $this->factory->createArgumentMetadata([new AttributeController(), 'issue41478']);\n        $this->assertEquals([\n            new ArgumentMetadata('baz', 'string', false, false, null, false, [new Foo('bar')], controllerName: AttributeController::class.'::issue41478'),\n            new ArgumentMetadata('bat', 'string', false, false, null, false, [], controllerName: AttributeController::class.'::issue41478'),\n        ], $arguments);\n    }\n\n    public function signature1(self $foo, array $bar, callable $baz)\n    {\n    }\n\n    public function signature2(?self $foo = null, ?FakeClassThatDoesNotExist $bar = null, ?ImportedAndFake $baz = null)\n    {\n    }\n\n    public function signature3(FakeClassThatDoesNotExist $bar, ImportedAndFake $baz)\n    {\n    }\n\n    public function signature4($foo = 'default', $bar = 500, $baz = [])\n    {\n    }\n\n    public function signature5(?array $foo = null, $bar = null)\n    {\n    }\n}\n"
  },
  {
    "path": "Tests/ControllerMetadata/ArgumentMetadataTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\ControllerMetadata;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute\\Foo;\n\nclass ArgumentMetadataTest extends TestCase\n{\n    public function testWithBcLayerWithDefault()\n    {\n        $argument = new ArgumentMetadata('foo', 'string', false, true, 'default value');\n\n        $this->assertFalse($argument->isNullable());\n    }\n\n    public function testDefaultValueAvailable()\n    {\n        $argument = new ArgumentMetadata('foo', 'string', false, true, 'default value', true);\n\n        $this->assertTrue($argument->isNullable());\n        $this->assertTrue($argument->hasDefaultValue());\n        $this->assertSame('default value', $argument->getDefaultValue());\n    }\n\n    public function testDefaultValueUnavailable()\n    {\n        $this->expectException(\\LogicException::class);\n        $argument = new ArgumentMetadata('foo', 'string', false, false, null, false);\n\n        $this->assertFalse($argument->isNullable());\n        $this->assertFalse($argument->hasDefaultValue());\n        $argument->getDefaultValue();\n    }\n\n    public function testGetAttributes()\n    {\n        $argument = new ArgumentMetadata('foo', 'string', false, true, 'default value', true, [new Foo('bar')]);\n        $this->assertEquals([new Foo('bar')], $argument->getAttributes());\n    }\n\n    public function testGetAttributesOfType()\n    {\n        $argument = new ArgumentMetadata('foo', 'string', false, true, 'default value', true, [new Foo('bar')]);\n        $this->assertEquals([new Foo('bar')], $argument->getAttributesOfType(Foo::class));\n    }\n}\n"
  },
  {
    "path": "Tests/DataCollector/Compiler.log",
    "content": "Symfony\\Component\\DependencyInjection\\Compiler\\RemovePrivateAliasesPass: Removed service \"Psr\\Container\\ContainerInterface\"; reason: private alias.\nSymfony\\Component\\DependencyInjection\\Compiler\\RemovePrivateAliasesPass: Removed service \"Symfony\\Component\\DependencyInjection\\ContainerInterface\"; reason: private alias.\nSome custom logging message\nWith ending :\n"
  },
  {
    "path": "Tests/DataCollector/ConfigDataCollectorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DataCollector;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Config\\Loader\\LoaderInterface;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\ConfigDataCollector;\nuse Symfony\\Component\\HttpKernel\\Kernel;\n\nclass ConfigDataCollectorTest extends TestCase\n{\n    public function testCollect()\n    {\n        $kernel = new KernelForTest('test', true);\n        $c = new ConfigDataCollector();\n        $c->setKernel($kernel);\n        $c->collect(new Request(), new Response());\n\n        $this->assertSame('test', $c->getEnv());\n        $this->assertTrue($c->isDebug());\n        $this->assertSame('config', $c->getName());\n        $this->assertMatchesRegularExpression('~^'.preg_quote($c->getPhpVersion(), '~').'~', \\PHP_VERSION);\n        $this->assertMatchesRegularExpression('~'.preg_quote((string) $c->getPhpVersionExtra(), '~').'$~', \\PHP_VERSION);\n        $this->assertSame(\\PHP_INT_SIZE * 8, $c->getPhpArchitecture());\n        $this->assertSame(class_exists(\\Locale::class, false) && \\Locale::getDefault() ? \\Locale::getDefault() : 'n/a', $c->getPhpIntlLocale());\n        $this->assertSame(date_default_timezone_get(), $c->getPhpTimezone());\n        $this->assertSame(Kernel::VERSION, $c->getSymfonyVersion());\n        $this->assertSame(4 === Kernel::MINOR_VERSION, $c->isSymfonyLts());\n        $this->assertNull($c->getToken());\n        $this->assertSame(\\extension_loaded('xdebug'), $c->hasXDebug());\n        $this->assertSame(\\extension_loaded('Zend OPcache') && filter_var(\\ini_get('opcache.enable'), \\FILTER_VALIDATE_BOOL), $c->hasZendOpcache());\n        $this->assertSame(\\extension_loaded('apcu') && filter_var(\\ini_get('apc.enabled'), \\FILTER_VALIDATE_BOOL), $c->hasApcu());\n        $this->assertSame(\\sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION), $c->getSymfonyMinorVersion());\n        $this->assertContains($c->getSymfonyState(), ['eol', 'eom', 'dev', 'stable']);\n\n        $eom = \\DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE)->format('F Y');\n        $eol = \\DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE)->format('F Y');\n        $this->assertSame($eom, $c->getSymfonyEom());\n        $this->assertSame($eol, $c->getSymfonyEol());\n    }\n\n    public function testCollectWithoutKernel()\n    {\n        $c = new ConfigDataCollector();\n        $c->collect(new Request(), new Response());\n\n        $this->assertSame('n/a', $c->getEnv());\n        $this->assertSame('n/a', $c->isDebug());\n        $this->assertSame('config', $c->getName());\n        $this->assertMatchesRegularExpression('~^'.preg_quote($c->getPhpVersion(), '~').'~', \\PHP_VERSION);\n        $this->assertMatchesRegularExpression('~'.preg_quote((string) $c->getPhpVersionExtra(), '~').'$~', \\PHP_VERSION);\n        $this->assertSame(\\PHP_INT_SIZE * 8, $c->getPhpArchitecture());\n        $this->assertSame(class_exists(\\Locale::class, false) && \\Locale::getDefault() ? \\Locale::getDefault() : 'n/a', $c->getPhpIntlLocale());\n        $this->assertSame(date_default_timezone_get(), $c->getPhpTimezone());\n        $this->assertSame(Kernel::VERSION, $c->getSymfonyVersion());\n        $this->assertSame(4 === Kernel::MINOR_VERSION, $c->isSymfonyLts());\n        $this->assertNull($c->getToken());\n        $this->assertSame(\\extension_loaded('xdebug'), $c->hasXDebug());\n        $this->assertSame(\\extension_loaded('Zend OPcache') && filter_var(\\ini_get('opcache.enable'), \\FILTER_VALIDATE_BOOL), $c->hasZendOpcache());\n        $this->assertSame(\\extension_loaded('apcu') && filter_var(\\ini_get('apc.enabled'), \\FILTER_VALIDATE_BOOL), $c->hasApcu());\n        $this->assertSame(\\sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION), $c->getSymfonyMinorVersion());\n        $this->assertContains($c->getSymfonyState(), ['eol', 'eom', 'dev', 'stable']);\n\n        $eom = \\DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE)->format('F Y');\n        $eol = \\DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE)->format('F Y');\n        $this->assertSame($eom, $c->getSymfonyEom());\n        $this->assertSame($eol, $c->getSymfonyEol());\n    }\n}\n\nclass KernelForTest extends Kernel\n{\n    public function registerBundles(): iterable\n    {\n    }\n\n    public function getBundles(): array\n    {\n        return [];\n    }\n\n    public function registerContainerConfiguration(LoaderInterface $loader): void\n    {\n    }\n\n    public function getProjectDir(): string\n    {\n        return __DIR__.'/../Fixtures';\n    }\n}\n"
  },
  {
    "path": "Tests/DataCollector/DataCollectorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DataCollector;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\DataCollector\\CloneVarDataCollector;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\UsePropertyInDestruct;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\WithPublicObjectProperty;\nuse Symfony\\Component\\VarDumper\\Cloner\\VarCloner;\n\nclass DataCollectorTest extends TestCase\n{\n    public function testCloneVarStringWithScheme()\n    {\n        $c = new CloneVarDataCollector('scheme://foo');\n        $c->collect(new Request(), new Response());\n        $cloner = new VarCloner();\n\n        $this->assertEquals($cloner->cloneVar('scheme://foo'), $c->getData());\n    }\n\n    public function testCloneVarExistingFilePath()\n    {\n        $c = new CloneVarDataCollector([$filePath = tempnam(sys_get_temp_dir(), 'clone_var_data_collector_')]);\n        $c->collect(new Request(), new Response());\n\n        $this->assertSame($filePath, $c->getData()[0]);\n    }\n\n    public function testClassPublicObjectProperty()\n    {\n        $parent = new WithPublicObjectProperty();\n        $child = new WithPublicObjectProperty();\n\n        $child->parent = $parent;\n\n        $c = new CloneVarDataCollector($child);\n        $c->collect(new Request(), new Response());\n\n        $this->assertNotNull($c->getData()->parent);\n    }\n\n    public function testClassPublicObjectPropertyAsReference()\n    {\n        $parent = new WithPublicObjectProperty();\n        $child = new WithPublicObjectProperty();\n\n        $child->parent = &$parent;\n\n        $c = new CloneVarDataCollector($child);\n        $c->collect(new Request(), new Response());\n\n        $this->assertNotNull($c->getData()->parent);\n    }\n\n    public function testClassUsePropertyInDestruct()\n    {\n        $parent = new UsePropertyInDestruct();\n        $child = new UsePropertyInDestruct();\n\n        $child->parent = $parent;\n\n        $c = new CloneVarDataCollector($child);\n        $c->collect(new Request(), new Response());\n\n        $this->assertNotNull($c->getData()->parent);\n    }\n\n    public function testClassUsePropertyAsReferenceInDestruct()\n    {\n        $parent = new UsePropertyInDestruct();\n        $child = new UsePropertyInDestruct();\n\n        $child->parent = &$parent;\n\n        $c = new CloneVarDataCollector($child);\n        $c->collect(new Request(), new Response());\n\n        $this->assertNotNull($c->getData()->parent);\n    }\n}\n"
  },
  {
    "path": "Tests/DataCollector/DumpDataCollectorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DataCollector;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\ErrorHandler\\ErrorRenderer\\FileLinkFormatter;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\DumpDataCollector;\nuse Symfony\\Component\\VarDumper\\Cloner\\Data;\nuse Symfony\\Component\\VarDumper\\Dumper\\CliDumper;\nuse Symfony\\Component\\VarDumper\\Server\\Connection;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass DumpDataCollectorTest extends TestCase\n{\n    public function testDump()\n    {\n        $data = new Data([[123]]);\n        $data = $data->withContext(['label' => 'foo']);\n\n        $collector = new DumpDataCollector(null, new FileLinkFormatter([]));\n\n        $this->assertSame('dump', $collector->getName());\n\n        $collector->dump($data);\n        $line = __LINE__ - 1;\n        $this->assertSame(1, $collector->getDumpsCount());\n\n        $dump = $collector->getDumps('html');\n        $this->assertArrayHasKey('data', $dump[0]);\n        $dump[0]['data'] = preg_replace('/^.*?<pre/', '<pre', $dump[0]['data']);\n        $dump[0]['data'] = preg_replace('/sf-dump-\\d+/', 'sf-dump', $dump[0]['data']);\n\n        $xDump = [\n            [\n                'data' => \"<pre class=sf-dump id=sf-dump data-indent-pad=\\\"  \\\"><span class=sf-dump-num>123</span>\\n</pre><script>Sfdump(\\\"sf-dump\\\")</script>\\n\",\n                'name' => 'DumpDataCollectorTest.php',\n                'file' => __FILE__,\n                'line' => $line,\n                'fileExcerpt' => false,\n                'label' => 'foo',\n            ],\n        ];\n        $this->assertEquals($xDump, $dump);\n\n        $this->assertStringMatchesFormat('%a;a:%d:{i:0;a:6:{s:4:\"data\";%c:39:\"Symfony\\Component\\VarDumper\\Cloner\\Data\":%a', serialize($collector));\n        $this->assertSame(0, $collector->getDumpsCount());\n\n        $serialized = serialize($collector);\n        $this->assertSame(\"O:60:\\\"Symfony\\Component\\HttpKernel\\DataCollector\\DumpDataCollector\\\":1:{s:4:\\\"data\\\";a:2:{i:0;b:0;i:1;s:5:\\\"UTF-8\\\";}}\", $serialized);\n\n        $this->assertInstanceOf(DumpDataCollector::class, unserialize($serialized));\n    }\n\n    public function testDumpWithServerConnection()\n    {\n        $data = new Data([[123]]);\n\n        // Server is up, server dumper is used\n        $serverDumper = $this->createMock(Connection::class);\n        $serverDumper->expects($this->once())->method('write')->willReturn(true);\n\n        $collector = new DumpDataCollector(null, null, null, null, $serverDumper);\n        $collector->dump($data);\n\n        // Collect doesn't re-trigger dump\n        ob_start();\n        $collector->collect(new Request(), new Response());\n        $this->assertSame('', ob_get_clean());\n        $this->assertStringMatchesFormat('%a;a:%d:{i:0;a:6:{s:4:\"data\";%c:39:\"Symfony\\Component\\VarDumper\\Cloner\\Data\":%a', serialize($collector));\n    }\n\n    public function testCollectDefault()\n    {\n        $data = new Data([[123]]);\n\n        $collector = new DumpDataCollector();\n\n        $collector->dump($data);\n        $line = __LINE__ - 1;\n\n        ob_start();\n        $collector->collect(new Request(), new Response());\n        $output = preg_replace(\"/\\033\\[[^m]*m/\", '', ob_get_clean());\n\n        $this->assertSame(\"DumpDataCollectorTest.php on line {$line}:\\n123\\n\", $output);\n        $this->assertSame(1, $collector->getDumpsCount());\n        serialize($collector);\n    }\n\n    public function testCollectHtml()\n    {\n        $data = new Data([[123]]);\n\n        $collector = new DumpDataCollector(null, 'test://%f:%l');\n\n        $collector->dump($data);\n        $line = __LINE__ - 1;\n        $file = __FILE__;\n        $xOutput = <<<EOTXT\n            <pre class=sf-dump id=sf-dump data-indent-pad=\"  \"><a href=\"test://{$file}:{$line}\" title=\"{$file}\"><span class=sf-dump-meta>DumpDataCollectorTest.php</span></a> on line <span class=sf-dump-meta>{$line}</span>:\n            <span class=sf-dump-num>123</span>\n            </pre>\n            EOTXT;\n\n        ob_start();\n        $response = new Response();\n        $response->headers->set('Content-Type', 'text/html');\n        $collector->collect(new Request(), $response);\n        $output = ob_get_clean();\n        $output = preg_replace('#<(script|style).*?</\\1>#s', '', $output);\n        $output = preg_replace('/sf-dump-\\d+/', 'sf-dump', $output);\n\n        $this->assertSame($xOutput, trim($output));\n        $this->assertSame(1, $collector->getDumpsCount());\n        serialize($collector);\n    }\n\n    public function testFlush()\n    {\n        $data = new Data([[456]]);\n        $collector = new DumpDataCollector();\n        $collector->dump($data);\n        $line = __LINE__ - 1;\n\n        ob_start();\n        $collector->__destruct();\n        $output = preg_replace(\"/\\033\\[[^m]*m/\", '', ob_get_clean());\n        $this->assertSame(\"DumpDataCollectorTest.php on line {$line}:\\n456\\n\", $output);\n    }\n\n    public function testFlushNothingWhenDataDumperIsProvided()\n    {\n        $data = new Data([[456]]);\n        $dumper = new CliDumper('php://output');\n        $collector = new DumpDataCollector(null, null, null, null, $dumper);\n\n        ob_start();\n        $collector->dump($data);\n        $line = __LINE__ - 1;\n        $output = preg_replace(\"/\\033\\[[^m]*m/\", '', ob_get_clean());\n\n        $this->assertSame(\"DumpDataCollectorTest.php on line {$line}:\\n456\\n\", $output);\n\n        ob_start();\n        $collector->__destruct();\n        $this->assertSame('', ob_get_clean());\n    }\n\n    public function testNullContentTypeWithNoDebugEnv()\n    {\n        $request = new Request();\n        $requestStack = new RequestStack();\n        $requestStack->push($request);\n\n        $response = new Response('<html><head></head><body></body></html>');\n        $response->headers->set('Content-Type', null);\n        $response->headers->set('X-Debug-Token', 'xxxxxxxx');\n\n        $collector = new DumpDataCollector(null, null, null, $requestStack);\n        $collector->collect($request, $response);\n\n        ob_start();\n        $collector->__destruct();\n        $this->assertSame('', ob_get_clean());\n    }\n}\n"
  },
  {
    "path": "Tests/DataCollector/ExceptionDataCollectorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DataCollector;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\ErrorHandler\\Exception\\FlattenException;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\ExceptionDataCollector;\n\nclass ExceptionDataCollectorTest extends TestCase\n{\n    public function testCollect()\n    {\n        $e = new \\Exception('foo', 500);\n        $c = new ExceptionDataCollector();\n        $flattened = FlattenException::createWithDataRepresentation($e);\n        $trace = $flattened->getTrace();\n\n        $this->assertFalse($c->hasException());\n\n        $c->collect(new Request(), new Response(), $e);\n\n        $this->assertTrue($c->hasException());\n        $this->assertEquals($flattened, $c->getException());\n        $this->assertSame('foo', $c->getMessage());\n        $this->assertSame(500, $c->getCode());\n        $this->assertSame('exception', $c->getName());\n        $this->assertSame($trace, $c->getTrace());\n\n        $c->collect(new Request(), new Response(), new class extends \\Exception {\n            protected $code = 'non-integer-code';\n        });\n\n        $this->assertSame('non-integer-code', $c->getCode());\n    }\n\n    public function testCollectWithoutException()\n    {\n        $c = new ExceptionDataCollector();\n        $c->collect(new Request(), new Response());\n\n        $this->assertFalse($c->hasException());\n    }\n\n    public function testReset()\n    {\n        $c = new ExceptionDataCollector();\n\n        $c->collect(new Request(), new Response(), new \\Exception());\n        $c->reset();\n        $c->collect(new Request(), new Response());\n\n        $this->assertFalse($c->hasException());\n    }\n}\n"
  },
  {
    "path": "Tests/DataCollector/LoggerDataCollectorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DataCollector;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\ErrorHandler\\Exception\\SilencedErrorContext;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\LoggerDataCollector;\nuse Symfony\\Component\\HttpKernel\\Log\\DebugLoggerInterface;\nuse Symfony\\Component\\VarDumper\\Cloner\\Data;\n\nclass LoggerDataCollectorTest extends TestCase\n{\n    public function testCollectWithUnexpectedFormat()\n    {\n        $logger = $this\n            ->getMockBuilder(DebugLoggerInterface::class)\n            ->onlyMethods(['countErrors', 'getLogs', 'clear'])\n            ->getMock();\n        $logger->expects($this->once())->method('countErrors')->willReturn(123);\n        $logger->expects($this->exactly(2))->method('getLogs')->willReturn([]);\n\n        $c = new LoggerDataCollector($logger, __DIR__.'/');\n        $c->lateCollect();\n        $compilerLogs = $c->getCompilerLogs()->getValue(true);\n\n        $this->assertSame([\n            ['message' => 'Removed service \"Psr\\Container\\ContainerInterface\"; reason: private alias.'],\n            ['message' => 'Removed service \"Symfony\\Component\\DependencyInjection\\ContainerInterface\"; reason: private alias.'],\n        ], $compilerLogs['Symfony\\Component\\DependencyInjection\\Compiler\\RemovePrivateAliasesPass']);\n\n        $this->assertSame([\n            ['message' => 'Some custom logging message'],\n            ['message' => 'With ending :'],\n        ], $compilerLogs['Unknown Compiler Pass']);\n    }\n\n    public function testCollectFromDeprecationsLog()\n    {\n        $containerPathPrefix = __DIR__.'/';\n        $path = $containerPathPrefix.'Deprecations.log';\n        touch($path);\n        file_put_contents($path, serialize([[\n            'type' => 16384,\n            'message' => 'The \"Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller\" class is deprecated since Symfony 4.2, use Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController instead.',\n            'file' => '/home/hamza/project/contrib/sf/vendor/symfony/framework-bundle/Controller/Controller.php',\n            'line' => 17,\n            'trace' => [[\n                'file' => '/home/hamza/project/contrib/sf/src/Controller/DefaultController.php',\n                'line' => 9,\n                'function' => 'spl_autoload_call',\n            ]],\n            'count' => 1,\n        ]]));\n\n        $logger = $this\n            ->getMockBuilder(DebugLoggerInterface::class)\n            ->onlyMethods(['countErrors', 'getLogs', 'clear'])\n            ->getMock();\n\n        $logger->expects($this->once())->method('countErrors')->willReturn(0);\n        $logger->expects($this->exactly(2))->method('getLogs')->willReturn([]);\n\n        $c = new LoggerDataCollector($logger, $containerPathPrefix);\n        $c->lateCollect();\n\n        $processedLogs = $c->getProcessedLogs();\n\n        $this->assertCount(1, $processedLogs);\n\n        $this->assertSame('deprecation', $processedLogs[0]['type']);\n        $this->assertSame(1, $processedLogs[0]['errorCount']);\n        $this->assertSame($processedLogs[0]['timestamp'], (new \\DateTimeImmutable())->setTimestamp(filemtime($path))->format(\\DateTimeInterface::RFC3339_EXTENDED));\n        $this->assertSame(100, $processedLogs[0]['priority']);\n        $this->assertSame('DEBUG', $processedLogs[0]['priorityName']);\n        $this->assertNull($processedLogs[0]['channel']);\n\n        $this->assertInstanceOf(Data::class, $processedLogs[0]['message']);\n        $this->assertInstanceOf(Data::class, $processedLogs[0]['context']);\n\n        @unlink($path);\n    }\n\n    public function testWithMainRequest()\n    {\n        $mainRequest = new Request();\n        $stack = new RequestStack();\n        $stack->push($mainRequest);\n\n        $logger = $this\n            ->getMockBuilder(DebugLoggerInterface::class)\n            ->onlyMethods(['countErrors', 'getLogs', 'clear'])\n            ->getMock();\n        $logger->expects($this->once())->method('countErrors')->with(null);\n        $logger->expects($this->exactly(2))->method('getLogs')->with(null)->willReturn([]);\n\n        $c = new LoggerDataCollector($logger, __DIR__.'/', $stack);\n\n        $c->collect($mainRequest, new Response());\n        $c->lateCollect();\n    }\n\n    public function testWithSubRequest()\n    {\n        $mainRequest = new Request();\n        $subRequest = new Request();\n        $stack = new RequestStack();\n        $stack->push($mainRequest);\n        $stack->push($subRequest);\n\n        $logger = $this\n            ->getMockBuilder(DebugLoggerInterface::class)\n            ->onlyMethods(['countErrors', 'getLogs', 'clear'])\n            ->getMock();\n        $logger->expects($this->once())->method('countErrors')->with($subRequest);\n        $logger->expects($this->exactly(2))->method('getLogs')->with($subRequest)->willReturn([]);\n\n        $c = new LoggerDataCollector($logger, __DIR__.'/', $stack);\n\n        $c->collect($subRequest, new Response());\n        $c->lateCollect();\n    }\n\n    #[DataProvider('getCollectTestData')]\n    public function testCollect($nb, $logs, $expectedLogs, $expectedDeprecationCount, $expectedScreamCount, $expectedPriorities = null)\n    {\n        $logger = $this\n            ->getMockBuilder(DebugLoggerInterface::class)\n            ->onlyMethods(['countErrors', 'getLogs', 'clear'])\n            ->getMock();\n        $logger->expects($this->once())->method('countErrors')->willReturn($nb);\n        $logger->expects($this->exactly(2))->method('getLogs')->willReturn($logs);\n\n        $c = new LoggerDataCollector($logger);\n        $c->lateCollect();\n\n        $this->assertEquals('logger', $c->getName());\n        $this->assertEquals($nb, $c->countErrors());\n\n        $logs = array_map(static function ($v) {\n            if (isset($v['context']['exception'])) {\n                $e = &$v['context']['exception'];\n                $e = isset($e[\"\\0*\\0message\"]) ? [$e[\"\\0*\\0message\"], $e[\"\\0*\\0severity\"]] : [$e[\"\\0Symfony\\Component\\ErrorHandler\\Exception\\SilencedErrorContext\\0severity\"]];\n            }\n\n            return $v;\n        }, $c->getLogs()->getValue(true));\n        $this->assertEquals($expectedLogs, $logs);\n        $this->assertEquals($expectedDeprecationCount, $c->countDeprecations());\n        $this->assertEquals($expectedScreamCount, $c->countScreams());\n\n        if (isset($expectedPriorities)) {\n            $this->assertSame($expectedPriorities, $c->getPriorities()->getValue(true));\n        }\n    }\n\n    public static function getCollectTestData()\n    {\n        yield 'simple log' => [\n            1,\n            [['message' => 'foo', 'context' => [], 'priority' => 100, 'priorityName' => 'DEBUG']],\n            [['message' => 'foo', 'context' => [], 'priority' => 100, 'priorityName' => 'DEBUG']],\n            0,\n            0,\n        ];\n\n        yield 'log with a context' => [\n            1,\n            [['message' => 'foo', 'context' => ['foo' => 'bar'], 'priority' => 100, 'priorityName' => 'DEBUG']],\n            [['message' => 'foo', 'context' => ['foo' => 'bar'], 'priority' => 100, 'priorityName' => 'DEBUG']],\n            0,\n            0,\n        ];\n\n        yield 'logs with some deprecations' => [\n            1,\n            [\n                ['message' => 'foo3', 'context' => ['exception' => new \\ErrorException('warning', 0, \\E_USER_WARNING)], 'priority' => 100, 'priorityName' => 'DEBUG'],\n                ['message' => 'foo', 'context' => ['exception' => new \\ErrorException('deprecated', 0, \\E_DEPRECATED)], 'priority' => 100, 'priorityName' => 'DEBUG'],\n                ['message' => 'foo2', 'context' => ['exception' => new \\ErrorException('deprecated', 0, \\E_USER_DEPRECATED)], 'priority' => 100, 'priorityName' => 'DEBUG'],\n            ],\n            [\n                ['message' => 'foo3', 'context' => ['exception' => ['warning', \\E_USER_WARNING]], 'priority' => 100, 'priorityName' => 'DEBUG'],\n                ['message' => 'foo', 'context' => ['exception' => ['deprecated', \\E_DEPRECATED]], 'priority' => 100, 'priorityName' => 'DEBUG', 'errorCount' => 1, 'scream' => false],\n                ['message' => 'foo2', 'context' => ['exception' => ['deprecated', \\E_USER_DEPRECATED]], 'priority' => 100, 'priorityName' => 'DEBUG', 'errorCount' => 1, 'scream' => false],\n            ],\n            2,\n            0,\n            [100 => ['count' => 3, 'name' => 'DEBUG']],\n        ];\n\n        yield 'logs with some silent errors' => [\n            1,\n            [\n                ['message' => 'foo3', 'context' => ['exception' => new \\ErrorException('warning', 0, \\E_USER_WARNING)], 'priority' => 100, 'priorityName' => 'DEBUG'],\n                ['message' => 'foo3', 'context' => ['exception' => new SilencedErrorContext(\\E_USER_WARNING, __FILE__, __LINE__)], 'priority' => 100, 'priorityName' => 'DEBUG'],\n                ['message' => '0', 'context' => ['exception' => new SilencedErrorContext(\\E_USER_WARNING, __FILE__, __LINE__)], 'priority' => 100, 'priorityName' => 'DEBUG'],\n            ],\n            [\n                ['message' => 'foo3', 'context' => ['exception' => ['warning', \\E_USER_WARNING]], 'priority' => 100, 'priorityName' => 'DEBUG'],\n                ['message' => 'foo3', 'context' => ['exception' => [\\E_USER_WARNING]], 'priority' => 100, 'priorityName' => 'DEBUG', 'errorCount' => 1, 'scream' => true],\n                ['message' => '0', 'context' => ['exception' => [\\E_USER_WARNING]], 'priority' => 100, 'priorityName' => 'DEBUG', 'errorCount' => 1, 'scream' => true],\n            ],\n            0,\n            2,\n        ];\n    }\n}\n"
  },
  {
    "path": "Tests/DataCollector/MemoryDataCollectorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DataCollector;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\MemoryDataCollector;\n\nclass MemoryDataCollectorTest extends TestCase\n{\n    public function testCollect()\n    {\n        $collector = new MemoryDataCollector();\n        $collector->collect(new Request(), new Response());\n\n        $this->assertIsInt($collector->getMemory());\n        $this->assertIsInt($collector->getMemoryLimit());\n        $this->assertSame('memory', $collector->getName());\n    }\n\n    #[DataProvider('getBytesConversionTestData')]\n    public function testBytesConversion($limit, $bytes)\n    {\n        $collector = new MemoryDataCollector();\n        $method = new \\ReflectionMethod($collector, 'convertToBytes');\n        $this->assertEquals($bytes, $method->invoke($collector, $limit));\n    }\n\n    public static function getBytesConversionTestData()\n    {\n        return [\n            ['2k', 2048],\n            ['2 k', 2048],\n            ['8m', 8 * 1024 * 1024],\n            ['+2 k', 2048],\n            ['+2???k', 2048],\n            ['0x10', 16],\n            ['0xf', 15],\n            ['010', 8],\n            ['+0x10 k', 16 * 1024],\n            ['1g', 1024 * 1024 * 1024],\n            ['1G', 1024 * 1024 * 1024],\n            ['-1', -1],\n            ['0', 0],\n            ['2mk', 2048], // the unit must be the last char, so in this case 'k', not 'm'\n        ];\n    }\n}\n"
  },
  {
    "path": "Tests/DataCollector/RequestDataCollectorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DataCollector;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\EventDispatcher\\EventDispatcher;\nuse Symfony\\Component\\HttpFoundation\\Cookie;\nuse Symfony\\Component\\HttpFoundation\\ParameterBag;\nuse Symfony\\Component\\HttpFoundation\\RedirectResponse;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpFoundation\\Session\\Session;\nuse Symfony\\Component\\HttpFoundation\\Session\\SessionInterface;\nuse Symfony\\Component\\HttpFoundation\\Session\\Storage\\MetadataBag;\nuse Symfony\\Component\\HttpFoundation\\Session\\Storage\\MockArraySessionStorage;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolverInterface;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\RequestDataCollector;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\HttpKernel;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\DataCollector\\DummyController;\n\nclass RequestDataCollectorTest extends TestCase\n{\n    public function testCollect()\n    {\n        $c = new RequestDataCollector();\n\n        $c->collect($request = $this->createRequest(), $this->createResponse());\n        $c->lateCollect();\n\n        $attributes = $c->getRequestAttributes();\n\n        $this->assertSame('request', $c->getName());\n        $this->assertInstanceOf(ParameterBag::class, $c->getRequestHeaders());\n        $this->assertInstanceOf(ParameterBag::class, $c->getRequestServer());\n        $this->assertInstanceOf(ParameterBag::class, $c->getRequestCookies());\n        $this->assertInstanceOf(ParameterBag::class, $attributes);\n        $this->assertInstanceOf(ParameterBag::class, $c->getRequestRequest());\n        $this->assertInstanceOf(ParameterBag::class, $c->getRequestQuery());\n        $this->assertInstanceOf(ParameterBag::class, $c->getResponseCookies());\n        $this->assertSame('html', $c->getFormat());\n        $this->assertEquals('foobar', $c->getRoute());\n        $this->assertEquals(['name' => 'foo'], $c->getRouteParams());\n        $this->assertSame([], $c->getSessionAttributes());\n        $this->assertSame('en', $c->getLocale());\n        $this->assertContainsEquals(__FILE__, $attributes->get('resource'));\n        $this->assertSame('stdClass', $attributes->get('object')->getType());\n\n        $this->assertInstanceOf(ParameterBag::class, $c->getResponseHeaders());\n        $this->assertSame('OK', $c->getStatusText());\n        $this->assertSame(200, $c->getStatusCode());\n        $this->assertSame('application/json', $c->getContentType());\n    }\n\n    public function testCollectWithoutRouteParams()\n    {\n        $request = $this->createRequest([]);\n\n        $c = new RequestDataCollector();\n        $c->collect($request, $this->createResponse());\n        $c->lateCollect();\n\n        $this->assertEquals([], $c->getRouteParams());\n    }\n\n    #[DataProvider('provideControllerCallables')]\n    public function testControllerInspection($name, $callable, $expected)\n    {\n        $c = new RequestDataCollector();\n        $request = $this->createRequest();\n        $response = $this->createResponse();\n        $this->injectController($c, $callable, $request);\n        $c->collect($request, $response);\n        $c->lateCollect();\n\n        $this->assertSame($expected, $c->getController()->getValue(true), \\sprintf('Testing: %s', $name));\n    }\n\n    public static function provideControllerCallables(): array\n    {\n        // make sure we always match the line number\n        $controller = new DummyController();\n\n        $r1 = new \\ReflectionMethod($controller, 'regularCallable');\n        $r2 = new \\ReflectionMethod($controller, 'staticControllerMethod');\n        $r3 = new \\ReflectionClass($controller);\n\n        // test name, callable, expected\n        return [\n            [\n                '\"Regular\" callable',\n                [$controller, 'regularCallable'],\n                [\n                    'class' => DummyController::class,\n                    'method' => 'regularCallable',\n                    'file' => $r1->getFileName(),\n                    'line' => $r1->getStartLine(),\n                ],\n            ],\n\n            [\n                'Closure',\n                static fn () => 'foo',\n                [\n                    'class' => \\sprintf('{closure:%s():%d}', __METHOD__, __LINE__ - 2),\n                    'method' => null,\n                    'file' => __FILE__,\n                    'line' => __LINE__ - 5,\n                ],\n            ],\n\n            [\n                'First-class callable closure',\n                $controller->regularCallable(...),\n                [\n                    'class' => DummyController::class,\n                    'method' => 'regularCallable',\n                    'file' => $r1->getFileName(),\n                    'line' => $r1->getStartLine(),\n                ],\n            ],\n\n            [\n                'Static callback as string',\n                DummyController::class.'::staticControllerMethod',\n                [\n                    'class' => DummyController::class,\n                    'method' => 'staticControllerMethod',\n                    'file' => $r2->getFileName(),\n                    'line' => $r2->getStartLine(),\n                ],\n            ],\n\n            [\n                'Static callable with instance',\n                [$controller, 'staticControllerMethod'],\n                [\n                    'class' => DummyController::class,\n                    'method' => 'staticControllerMethod',\n                    'file' => $r2->getFileName(),\n                    'line' => $r2->getStartLine(),\n                ],\n            ],\n\n            [\n                'Static callable with class name',\n                [DummyController::class, 'staticControllerMethod'],\n                [\n                    'class' => DummyController::class,\n                    'method' => 'staticControllerMethod',\n                    'file' => $r2->getFileName(),\n                    'line' => $r2->getStartLine(),\n                ],\n            ],\n\n            [\n                'Callable with instance depending on __call()',\n                [$controller, 'magicMethod'],\n                [\n                    'class' => DummyController::class,\n                    'method' => 'magicMethod',\n                    'file' => 'n/a',\n                    'line' => 'n/a',\n                ],\n            ],\n\n            [\n                'Callable with class name depending on __callStatic()',\n                [DummyController::class, 'magicMethod'],\n                [\n                    'class' => DummyController::class,\n                    'method' => 'magicMethod',\n                    'file' => 'n/a',\n                    'line' => 'n/a',\n                ],\n            ],\n\n            [\n                'Invokable controller',\n                $controller,\n                [\n                    'class' => DummyController::class,\n                    'method' => null,\n                    'file' => $r3->getFileName(),\n                    'line' => $r3->getStartLine(),\n                ],\n            ],\n        ];\n    }\n\n    public function testItIgnoresInvalidCallables()\n    {\n        $request = $this->createRequestWithSession();\n        $response = new RedirectResponse('/');\n\n        $c = new RequestDataCollector();\n        $c->collect($request, $response);\n\n        $this->assertSame('n/a', $c->getController());\n    }\n\n    public function testItAddsRedirectedAttributesWhenRequestContainsSpecificCookie()\n    {\n        $request = $this->createRequest();\n        $request->cookies->add([\n            'sf_redirect' => '{}',\n        ]);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $c = new RequestDataCollector();\n        $c->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $this->createResponse()));\n\n        $this->assertTrue($request->attributes->get('_redirected'));\n    }\n\n    public function testItSetsARedirectCookieIfTheResponseIsARedirection()\n    {\n        $c = new RequestDataCollector();\n\n        $response = $this->createResponse();\n        $response->setStatusCode(302);\n        $response->headers->set('Location', '/somewhere-else');\n\n        $c->collect($request = $this->createRequest(), $response);\n        $c->lateCollect();\n\n        $cookie = $this->getCookieByName($response, 'sf_redirect');\n\n        $this->assertNotEmpty($cookie->getValue());\n        $this->assertSame('lax', $cookie->getSameSite());\n        $this->assertFalse($cookie->isSecure());\n    }\n\n    public function testItCollectsTheRedirectionAndClearTheCookie()\n    {\n        $c = new RequestDataCollector();\n\n        $request = $this->createRequest();\n        $request->attributes->set('_redirected', true);\n        $request->cookies->add([\n            'sf_redirect' => '{\"method\": \"POST\"}',\n        ]);\n\n        $c->collect($request, $response = $this->createResponse());\n        $c->lateCollect();\n\n        $this->assertEquals('POST', $c->getRedirect()['method']);\n\n        $cookie = $this->getCookieByName($response, 'sf_redirect');\n        $this->assertNull($cookie->getValue());\n    }\n\n    public function testItCollectsTheSessionTraceProperly()\n    {\n        $collector = new RequestDataCollector();\n        $request = $this->createRequest();\n\n        // RequestDataCollectorTest doesn't implement SessionInterface or SessionBagInterface, therefore should do nothing.\n        $collector->collectSessionUsage();\n\n        $collector->collect($request, $this->createResponse());\n        $this->assertSame([], $collector->getSessionUsages());\n\n        $collector->reset();\n\n        $session = $this->createStub(SessionInterface::class);\n        $session->method('getMetadataBag')->willReturnCallback(static function () use ($collector) {\n            $collector->collectSessionUsage();\n\n            return new MetadataBag();\n        });\n        $session->getMetadataBag();\n\n        $collector->collect($request, $this->createResponse());\n        $collector->lateCollect();\n\n        $usages = $collector->getSessionUsages();\n\n        $this->assertCount(1, $usages);\n        $this->assertSame(__FILE__, $usages[0]['file']);\n        $this->assertSame(__LINE__ - 9, $line = $usages[0]['line']);\n\n        $trace = $usages[0]['trace'];\n        $this->assertSame('getMetadataBag', $trace[0]['function']);\n        $this->assertSame(self::class, $class = $trace[1]['class']);\n\n        $this->assertSame(\\sprintf('%s:%s', $class, $line), $usages[0]['name']);\n    }\n\n    public function testStatelessCheck()\n    {\n        $requestStack = new RequestStack();\n        $request = $this->createRequest();\n        $requestStack->push($request);\n\n        $collector = new RequestDataCollector($requestStack);\n        $collector->collect($request, $response = $this->createResponse());\n        $collector->lateCollect();\n\n        $this->assertFalse($collector->getStatelessCheck());\n\n        $requestStack = new RequestStack();\n        $request = $this->createRequest();\n        $request->attributes->set('_stateless', true);\n        $requestStack->push($request);\n\n        $collector = new RequestDataCollector($requestStack);\n        $collector->collect($request, $response = $this->createResponse());\n        $collector->lateCollect();\n\n        $this->assertTrue($collector->getStatelessCheck());\n\n        $requestStack = new RequestStack();\n        $request = $this->createRequest();\n\n        $collector = new RequestDataCollector($requestStack);\n        $collector->collect($request, $response = $this->createResponse());\n        $collector->lateCollect();\n\n        $this->assertFalse($collector->getStatelessCheck());\n    }\n\n    public function testItHidesPassword()\n    {\n        $c = new RequestDataCollector();\n\n        $request = Request::create(\n            'http://test.com/login',\n            'POST',\n            ['_password' => ' _password@123'],\n            [],\n            [],\n            [],\n            '_password=%20_password%40123'\n        );\n\n        $c->collect($request, $this->createResponse());\n        $c->lateCollect();\n\n        $this->assertEquals('******', $c->getRequestRequest()->get('_password'));\n        $this->assertEquals('_password=******', $c->getContent());\n    }\n\n    protected function createRequest($routeParams = ['name' => 'foo'])\n    {\n        $request = Request::create('http://test.com/foo?bar=baz');\n        $request->attributes->set('foo', 'bar');\n        $request->attributes->set('_route', 'foobar');\n        $request->attributes->set('_route_params', $routeParams);\n        $request->attributes->set('resource', fopen(__FILE__, 'r'));\n        $request->attributes->set('object', new \\stdClass());\n\n        return $request;\n    }\n\n    private function createRequestWithSession()\n    {\n        $request = $this->createRequest();\n        $request->attributes->set('_controller', 'Foo::bar');\n        $request->setSession(new Session(new MockArraySessionStorage()));\n        $request->getSession()->start();\n\n        return $request;\n    }\n\n    protected function createResponse()\n    {\n        $response = new Response();\n        $response->setStatusCode(200);\n        $response->headers->set('Content-Type', 'application/json');\n        $response->headers->set('X-Foo-Bar', null);\n        $response->headers->setCookie(new Cookie('foo', 'bar', 1, '/foo', 'localhost', true, true, false, null));\n        $response->headers->setCookie(new Cookie('bar', 'foo', new \\DateTimeImmutable('@946684800'), '/', null, false, true, false, null));\n        $response->headers->setCookie(new Cookie('bazz', 'foo', '2000-12-12', '/', null, false, true, false, null));\n\n        return $response;\n    }\n\n    /**\n     * Inject the given controller callable into the data collector.\n     */\n    protected function injectController($collector, $controller, $request)\n    {\n        $resolver = $this->createStub(ControllerResolverInterface::class);\n        $httpKernel = new HttpKernel(new EventDispatcher(), $resolver, null, $this->createStub(ArgumentResolverInterface::class));\n        $event = new ControllerEvent($httpKernel, $controller, $request, HttpKernelInterface::MAIN_REQUEST);\n        $collector->onKernelController($event);\n    }\n\n    private function getCookieByName(Response $response, $name)\n    {\n        foreach ($response->headers->getCookies() as $cookie) {\n            if ($cookie->getName() == $name) {\n                return $cookie;\n            }\n        }\n\n        throw new \\InvalidArgumentException(\\sprintf('Cookie named \"%s\" is not in response', $name));\n    }\n\n    #[DataProvider('provideJsonContentTypes')]\n    public function testIsJson($contentType, $expected)\n    {\n        $response = $this->createResponse();\n        $request = $this->createRequest();\n        $request->headers->set('Content-Type', $contentType);\n\n        $c = new RequestDataCollector();\n        $c->collect($request, $response);\n\n        $this->assertSame($expected, $c->isJsonRequest());\n    }\n\n    public static function provideJsonContentTypes(): array\n    {\n        return [\n            ['text/csv', false],\n            ['application/json', true],\n            ['application/JSON', true],\n            ['application/hal+json', true],\n            ['application/xml+json', true],\n            ['application/xml', false],\n            ['', false],\n        ];\n    }\n\n    #[DataProvider('providePrettyJson')]\n    public function testGetPrettyJsonValidity($content, $expected)\n    {\n        $response = $this->createResponse();\n        $request = Request::create('/', 'POST', [], [], [], [], $content);\n\n        $c = new RequestDataCollector();\n        $c->collect($request, $response);\n\n        $this->assertSame($expected, $c->getPrettyJson());\n    }\n\n    public static function providePrettyJson(): array\n    {\n        return [\n            ['null', 'null'],\n            ['{ \"foo\": \"bar\" }', '{\n    \"foo\": \"bar\"\n}'],\n            ['{ \"abc\" }', null],\n            ['', null],\n        ];\n    }\n\n    public function testCurlCommandGet()\n    {\n        $request = Request::create('http://test.com/foo?bar=baz');\n\n        $c = new RequestDataCollector();\n        $c->collect($request, $this->createResponse());\n\n        $curlCommand = $c->getCurlCommand();\n        $this->assertStringStartsWith(\"curl \\\\\\n  --compressed\", $curlCommand);\n        $this->assertStringContainsString('--url '.('\\\\' === \\DIRECTORY_SEPARATOR ? '\"http://test.com/foo?bar=baz\"' : \"'http://test.com/foo?bar=baz'\"), $curlCommand);\n        $this->assertStringNotContainsString('--request', $curlCommand);\n    }\n\n    public function testCurlCommandPost()\n    {\n        $request = Request::create('http://test.com/foo', 'POST', [], [], [], [], '{\"key\":\"value\"}');\n\n        $c = new RequestDataCollector();\n        $c->collect($request, $this->createResponse());\n\n        $curlCommand = $c->getCurlCommand();\n        $this->assertStringContainsString('--request POST', $curlCommand);\n        $this->assertStringContainsString('--data-raw', $curlCommand);\n        $this->assertStringContainsString('\\\\' === \\DIRECTORY_SEPARATOR ? '\"{\"\"key\"\":\"\"value\"\"}\"' : '\\'{\"key\":\"value\"}\\'', $curlCommand);\n    }\n\n    public function testCurlCommandHead()\n    {\n        $request = Request::create('http://test.com/foo', 'HEAD');\n\n        $c = new RequestDataCollector();\n        $c->collect($request, $this->createResponse());\n\n        $curlCommand = $c->getCurlCommand();\n        $this->assertStringContainsString('--head', $curlCommand);\n        $this->assertStringNotContainsString('--request', $curlCommand);\n    }\n\n    public function testCurlCommandWithHeaders()\n    {\n        $request = Request::create('http://test.com/foo');\n        $request->headers->set('Accept', 'application/json');\n        $request->headers->set('X-Custom-Header', 'custom-value');\n\n        $c = new RequestDataCollector();\n        $c->collect($request, $this->createResponse());\n\n        $curlCommand = $c->getCurlCommand();\n        $this->assertStringContainsString('--header '.('\\\\' === \\DIRECTORY_SEPARATOR ? '\"Accept: application/json\"' : \"'Accept: application/json'\"), $curlCommand);\n        $this->assertStringContainsString('--header '.('\\\\' === \\DIRECTORY_SEPARATOR ? '\"X-Custom-Header: custom-value\"' : \"'X-Custom-Header: custom-value'\"), $curlCommand);\n        $this->assertStringNotContainsString('Host:', $curlCommand);\n    }\n\n    public function testCurlCommandWithCookies()\n    {\n        $request = Request::create('http://test.com/foo', 'GET', [], ['session' => 'abc123', 'lang' => 'en']);\n\n        $c = new RequestDataCollector();\n        $c->collect($request, $this->createResponse());\n\n        $curlCommand = $c->getCurlCommand();\n        $this->assertStringContainsString('--cookie', $curlCommand);\n        $this->assertStringContainsString('session=abc123', $curlCommand);\n        $this->assertStringContainsString('lang=en', $curlCommand);\n    }\n\n    public function testCurlCommandPutWithBody()\n    {\n        $request = Request::create('http://test.com/resource/1', 'PUT', [], [], [], [], 'updated data');\n\n        $c = new RequestDataCollector();\n        $c->collect($request, $this->createResponse());\n\n        $curlCommand = $c->getCurlCommand();\n        $this->assertStringContainsString('--request PUT', $curlCommand);\n        $this->assertStringContainsString('--data-raw', $curlCommand);\n    }\n\n    public function testCurlCommandDoesNotDuplicateQueryString()\n    {\n        $request = Request::create('http://test.com/path?foo=bar&baz=qux');\n\n        $c = new RequestDataCollector();\n        $c->collect($request, $this->createResponse());\n\n        $curlCommand = $c->getCurlCommand();\n        $this->assertSame(1, substr_count($curlCommand, 'foo=bar'));\n        $this->assertSame(1, substr_count($curlCommand, 'baz=qux'));\n    }\n\n    public function testCurlCommandGetWithNoBody()\n    {\n        $request = Request::create('http://test.com/foo', 'GET');\n\n        $c = new RequestDataCollector();\n        $c->collect($request, $this->createResponse());\n\n        $curlCommand = $c->getCurlCommand();\n        $this->assertStringNotContainsString('--data-raw', $curlCommand);\n    }\n\n    public function testCurlCommandIsEmptyStringWhenNotCollected()\n    {\n        $c = new RequestDataCollector();\n        $this->assertSame('', $c->getCurlCommand());\n    }\n}\n"
  },
  {
    "path": "Tests/DataCollector/RouterDataCollectorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DataCollector;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\RedirectResponse;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\RouterDataCollector;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerEvent;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\n\nclass RouterDataCollectorTest extends TestCase\n{\n    public function testRouteRedirectResponse()\n    {\n        $collector = new RouterDataCollector();\n\n        $request = Request::create('http://test.com/foo?bar=baz');\n        $response = new RedirectResponse('http://test.com/redirect');\n\n        $event = $this->createControllerEvent($request);\n\n        $collector->onKernelController($event);\n        $collector->collect($request, $response);\n\n        $this->assertTrue($collector->getRedirect());\n        $this->assertEquals('http://test.com/redirect', $collector->getTargetUrl());\n        $this->assertEquals('n/a', $collector->getTargetRoute());\n    }\n\n    public function testRouteNotRedirectResponse()\n    {\n        $collector = new RouterDataCollector();\n\n        $request = Request::create('http://test.com/foo?bar=baz');\n        $response = new Response('test');\n\n        $event = $this->createControllerEvent($request);\n\n        $collector->onKernelController($event);\n        $collector->collect($request, $response);\n\n        $this->assertFalse($collector->getRedirect());\n        $this->assertNull($collector->getTargetUrl());\n        $this->assertNull($collector->getTargetRoute());\n    }\n\n    public function testReset()\n    {\n        $collector = new RouterDataCollector();\n\n        // Fill Collector\n        $request = Request::create('http://test.com/foo?bar=baz');\n        $response = new RedirectResponse('http://test.com/redirect');\n        $event = $this->createControllerEvent($request);\n        $collector->onKernelController($event);\n        $collector->collect($request, $response);\n\n        $collector->reset();\n\n        $this->assertFalse($collector->getRedirect());\n        $this->assertNull($collector->getTargetUrl());\n        $this->assertNull($collector->getTargetRoute());\n    }\n\n    public function testGetName()\n    {\n        $collector = new RouterDataCollector();\n\n        $this->assertEquals('router', $collector->getName());\n    }\n\n    protected function createControllerEvent(Request $request): ControllerEvent\n    {\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        return new ControllerEvent($kernel, static function () {}, $request, null);\n    }\n}\n"
  },
  {
    "path": "Tests/DataCollector/TimeDataCollectorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DataCollector;\n\nuse PHPUnit\\Framework\\Attributes\\Group;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\TimeDataCollector;\nuse Symfony\\Component\\HttpKernel\\KernelInterface;\nuse Symfony\\Component\\Stopwatch\\Stopwatch;\nuse Symfony\\Component\\Stopwatch\\StopwatchEvent;\n\n#[Group('time-sensitive')]\nclass TimeDataCollectorTest extends TestCase\n{\n    public function testCollect()\n    {\n        $c = new TimeDataCollector();\n\n        $request = new Request();\n        $request->server->set('REQUEST_TIME', 1);\n\n        $c->collect($request, new Response());\n\n        $this->assertEquals(0, $c->getStartTime());\n\n        $request->server->set('REQUEST_TIME_FLOAT', 2);\n\n        $c->collect($request, new Response());\n\n        $this->assertEquals(2000, $c->getStartTime());\n\n        $request = new Request();\n        $c->collect($request, new Response());\n        $this->assertEquals(0, $c->getStartTime());\n\n        $kernel = $this->createMock(KernelInterface::class);\n        $kernel->expects($this->once())->method('getStartTime')->willReturn(123456.0);\n\n        $c = new TimeDataCollector($kernel);\n        $request = new Request();\n        $request->server->set('REQUEST_TIME', 1);\n\n        $c->collect($request, new Response());\n        $this->assertEquals(123456000, $c->getStartTime());\n        $this->assertSame(class_exists(Stopwatch::class, false), $c->isStopwatchInstalled());\n    }\n\n    public function testReset()\n    {\n        $collector = new TimeDataCollector();\n\n        // Fill Collector\n        $request = Request::create('http://test.com/foo?bar=baz');\n        $response = new Response('test');\n        $collector->collect($request, $response);\n\n        $collector->reset();\n\n        $this->assertEquals([], $collector->getEvents());\n        $this->assertEquals(0, $collector->getStartTime());\n        $this->assertFalse($collector->isStopwatchInstalled());\n    }\n\n    public function testLateCollect()\n    {\n        $stopwatch = new Stopwatch();\n        $stopwatch->start('test');\n\n        $collector = new TimeDataCollector(null, $stopwatch);\n\n        $request = new Request();\n        $request->attributes->set('_stopwatch_token', '__root__');\n\n        $collector->collect($request, new Response());\n        $collector->lateCollect();\n\n        $this->assertEquals(['test'], array_keys($collector->getEvents()));\n    }\n\n    public function testSetEvents()\n    {\n        $collector = new TimeDataCollector();\n\n        $event = $this->createMock(StopwatchEvent::class);\n        $event->expects($this->once())->method('ensureStopped');\n\n        $events = [$event];\n\n        $collector->setEvents($events);\n\n        $this->assertCount(1, $collector->getEvents());\n    }\n\n    public function testGetDurationHasEvents()\n    {\n        $collector = new TimeDataCollector();\n\n        $request = new Request();\n        $request->server->set('REQUEST_TIME_FLOAT', 1);\n        $collector->collect($request, new Response());\n\n        $event = $this->createMock(StopwatchEvent::class);\n        $event->expects($this->once())->method('getDuration')->willReturn(2000.0);\n        $event->expects($this->once())->method('getOrigin')->willReturn(1000.0);\n        $events = ['__section__' => $event];\n        $collector->setEvents($events);\n\n        $this->assertEquals(1000 + 2000 - 1000, $collector->getDuration());\n    }\n\n    public function testGetDurationNotEvents()\n    {\n        $collector = new TimeDataCollector();\n\n        $this->assertEquals(0, $collector->getDuration());\n    }\n\n    public function testGetInitTimeNotEvents()\n    {\n        $collector = new TimeDataCollector();\n\n        $this->assertEquals(0, $collector->getInitTime());\n    }\n\n    public function testGetInitTimeHasEvents()\n    {\n        $collector = new TimeDataCollector();\n\n        $request = new Request();\n        $request->server->set('REQUEST_TIME_FLOAT', 1);\n        $collector->collect($request, new Response());\n\n        $event = $this->createMock(StopwatchEvent::class);\n        $event->expects($this->once())->method('getOrigin')->willReturn(2000.0);\n        $events = ['__section__' => $event];\n        $collector->setEvents($events);\n\n        $this->assertEquals(2000 - 1000, $collector->getInitTime());\n    }\n\n    public function testGetName()\n    {\n        $collector = new TimeDataCollector();\n\n        $this->assertEquals('time', $collector->getName());\n    }\n}\n"
  },
  {
    "path": "Tests/Debug/ErrorHandlerConfiguratorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Debug;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LogLevel;\nuse Psr\\Log\\NullLogger;\nuse Symfony\\Component\\ErrorHandler\\ErrorHandler;\nuse Symfony\\Component\\HttpKernel\\Debug\\ErrorHandlerConfigurator;\n\nclass ErrorHandlerConfiguratorTest extends TestCase\n{\n    public function testConfigure()\n    {\n        $logger = new NullLogger();\n        $configurator = new ErrorHandlerConfigurator($logger);\n        $handler = new ErrorHandler();\n\n        $configurator->configure($handler);\n\n        $loggers = $handler->setLoggers([]);\n\n        $this->assertArrayHasKey(\\E_DEPRECATED, $loggers);\n        $this->assertSame([$logger, LogLevel::INFO], $loggers[\\E_DEPRECATED]);\n    }\n\n    #[DataProvider('provideLevelsAssignedToLoggers')]\n    public function testLevelsAssignedToLoggers(bool $hasLogger, bool $hasDeprecationLogger, array|int $levels, array|int|null $expectedLoggerLevels, array|int|null $expectedDeprecationLoggerLevels)\n    {\n        $handler = $this->createMock(ErrorHandler::class);\n\n        $expectedCalls = [];\n        $logger = null;\n        $deprecationLogger = null;\n\n        if ($hasDeprecationLogger) {\n            $deprecationLogger = new NullLogger();\n            if (null !== $expectedDeprecationLoggerLevels) {\n                $expectedCalls[] = [$deprecationLogger, $expectedDeprecationLoggerLevels, false];\n            }\n        }\n\n        if ($hasLogger) {\n            $logger = new NullLogger();\n            if (null !== $expectedLoggerLevels) {\n                $expectedCalls[] = [$logger, $expectedLoggerLevels, false];\n            }\n        }\n\n        $handler\n            ->expects($this->exactly(\\count($expectedCalls)))\n            ->method('setDefaultLogger')\n            ->willReturnCallback(function (...$args) use (&$expectedCalls) {\n                $this->assertSame(array_shift($expectedCalls), $args);\n            })\n        ;\n\n        $configurator = new ErrorHandlerConfigurator($logger, $levels, null, true, true, $deprecationLogger);\n\n        $configurator->configure($handler);\n    }\n\n    public static function provideLevelsAssignedToLoggers(): iterable\n    {\n        yield [false, false, 0, null, null];\n        yield [false, false, \\E_ALL, null, null];\n        yield [false, false, [], null, null];\n        yield [false, false, [\\E_WARNING => LogLevel::WARNING, \\E_USER_DEPRECATED => LogLevel::NOTICE], null, null];\n\n        yield [true, false, \\E_ALL, \\E_ALL, null];\n        yield [true, false, \\E_DEPRECATED, \\E_DEPRECATED, null];\n        yield [true, false, [], null, null];\n        yield [true, false, [\\E_WARNING => LogLevel::WARNING, \\E_DEPRECATED => LogLevel::NOTICE], [\\E_WARNING => LogLevel::WARNING, \\E_DEPRECATED => LogLevel::NOTICE], null];\n\n        yield [false, true, 0, null, null];\n        yield [false, true, \\E_ALL, null, \\E_DEPRECATED | \\E_USER_DEPRECATED];\n        yield [false, true, \\E_ERROR, null, null];\n        yield [false, true, [], null, null];\n        yield [false, true, [\\E_ERROR => LogLevel::ERROR, \\E_DEPRECATED => LogLevel::DEBUG], null, [\\E_DEPRECATED => LogLevel::DEBUG]];\n\n        yield [true, true, 0, null, null];\n        yield [true, true, \\E_ALL, \\E_ALL & ~(\\E_DEPRECATED | \\E_USER_DEPRECATED), \\E_DEPRECATED | \\E_USER_DEPRECATED];\n        yield [true, true, \\E_ERROR, \\E_ERROR, null];\n        yield [true, true, \\E_USER_DEPRECATED, null, \\E_USER_DEPRECATED];\n        yield [true, true, [\\E_ERROR => LogLevel::ERROR, \\E_DEPRECATED => LogLevel::DEBUG], [\\E_ERROR => LogLevel::ERROR], [\\E_DEPRECATED => LogLevel::DEBUG]];\n        yield [true, true, [\\E_ERROR => LogLevel::ALERT], [\\E_ERROR => LogLevel::ALERT], null];\n        yield [true, true, [\\E_USER_DEPRECATED => LogLevel::NOTICE], null, [\\E_USER_DEPRECATED => LogLevel::NOTICE]];\n    }\n}\n"
  },
  {
    "path": "Tests/Debug/TraceableEventDispatcherTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Debug;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\EventDispatcher\\EventDispatcher;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolverInterface;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface;\nuse Symfony\\Component\\HttpKernel\\Debug\\TraceableEventDispatcher;\nuse Symfony\\Component\\HttpKernel\\HttpKernel;\nuse Symfony\\Component\\Stopwatch\\Stopwatch;\nuse Symfony\\Contracts\\EventDispatcher\\Event;\n\nclass TraceableEventDispatcherTest extends TestCase\n{\n    public function testStopwatchSections()\n    {\n        $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), $stopwatch = new Stopwatch());\n        $kernel = $this->getHttpKernel($dispatcher);\n        $request = Request::create('/');\n        $response = $kernel->handle($request);\n        $kernel->terminate($request, $response);\n\n        $events = $stopwatch->getSectionEvents($request->attributes->get('_stopwatch_token'));\n        $this->assertEquals([\n            '__section__',\n            'kernel.request',\n            'kernel.controller',\n            'kernel.controller_arguments',\n            'controller',\n            'kernel.response',\n            'kernel.terminate',\n        ], array_keys($events));\n    }\n\n    public function testStopwatchCheckControllerOnRequestEvent()\n    {\n        $stopwatch = $this->getMockBuilder(Stopwatch::class)\n            ->onlyMethods(['isStarted'])\n            ->getMock();\n        $stopwatch->expects($this->once())\n            ->method('isStarted')\n            ->willReturn(false);\n\n        $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), $stopwatch);\n\n        $kernel = $this->getHttpKernel($dispatcher);\n        $request = Request::create('/');\n        $kernel->handle($request);\n    }\n\n    public function testStopwatchStopControllerOnRequestEvent()\n    {\n        $stopwatch = $this->getMockBuilder(Stopwatch::class)\n            ->onlyMethods(['isStarted', 'stop'])\n            ->getMock();\n        $stopwatch->expects($this->once())\n            ->method('isStarted')\n            ->willReturn(true);\n        $stopwatch->expects($this->exactly(3))\n            ->method('stop');\n\n        $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), $stopwatch);\n\n        $kernel = $this->getHttpKernel($dispatcher);\n        $request = Request::create('/');\n        $kernel->handle($request);\n    }\n\n    public function testAddListenerNested()\n    {\n        $called1 = false;\n        $called2 = false;\n        $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());\n        $dispatcher->addListener('my-event', static function () use ($dispatcher, &$called1, &$called2) {\n            $called1 = true;\n            $dispatcher->addListener('my-event', static function () use (&$called2) {\n                $called2 = true;\n            });\n        });\n        $dispatcher->dispatch(new Event(), 'my-event');\n        $this->assertTrue($called1);\n        $this->assertFalse($called2);\n        $dispatcher->dispatch(new Event(), 'my-event');\n        $this->assertTrue($called2);\n    }\n\n    public function testListenerCanRemoveItselfWhenExecuted()\n    {\n        $eventDispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());\n        $listener1 = static function () use ($eventDispatcher, &$listener1) {\n            $eventDispatcher->removeListener('foo', $listener1);\n        };\n        $eventDispatcher->addListener('foo', $listener1);\n        $eventDispatcher->addListener('foo', static function () {});\n        $eventDispatcher->dispatch(new Event(), 'foo');\n\n        $this->assertCount(1, $eventDispatcher->getListeners('foo'), 'expected listener1 to be removed');\n    }\n\n    protected function getHttpKernel($dispatcher)\n    {\n        $controllerResolver = $this->createMock(ControllerResolverInterface::class);\n        $controllerResolver->expects($this->once())->method('getController')->willReturn(static fn () => new Response());\n        $argumentResolver = $this->createMock(ArgumentResolverInterface::class);\n        $argumentResolver->expects($this->once())->method('getArguments')->willReturn([]);\n\n        return new HttpKernel($dispatcher, $controllerResolver, new RequestStack(), $argumentResolver);\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/ControllerArgumentValueResolverPassTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DependencyInjection;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Definition;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\nuse Symfony\\Component\\HttpKernel\\DependencyInjection\\ControllerArgumentValueResolverPass;\nuse Symfony\\Component\\Stopwatch\\Stopwatch;\n\nclass ControllerArgumentValueResolverPassTest extends TestCase\n{\n    public function testServicesAreOrderedAccordingToPriority()\n    {\n        $services = [\n            'n3' => [[]],\n            'n1' => [['priority' => 200]],\n            'n2' => [['priority' => 100]],\n        ];\n\n        $expected = [\n            new Reference('n1'),\n            new Reference('n2'),\n            new Reference('n3'),\n        ];\n\n        $definition = new Definition(ArgumentResolver::class, [null, []]);\n        $container = new ContainerBuilder();\n        $container->setDefinition('argument_resolver', $definition);\n\n        foreach ($services as $id => [$tag]) {\n            $container->register($id)->addTag('controller.argument_value_resolver', $tag);\n        }\n\n        $container->setParameter('kernel.debug', false);\n\n        (new ControllerArgumentValueResolverPass())->process($container);\n        $this->assertEquals($expected, $definition->getArgument(1)->getValues());\n\n        $this->assertFalse($container->hasDefinition('n1.traceable'));\n        $this->assertFalse($container->hasDefinition('n2.traceable'));\n        $this->assertFalse($container->hasDefinition('n3.traceable'));\n    }\n\n    public function testInDebugWithStopWatchDefinition()\n    {\n        $services = [\n            'n3' => [[]],\n            'n1' => [['priority' => 200]],\n            'n2' => [['priority' => 100]],\n        ];\n\n        $expected = [\n            new Reference('.debug.value_resolver.n1'),\n            new Reference('.debug.value_resolver.n2'),\n            new Reference('.debug.value_resolver.n3'),\n        ];\n\n        $definition = new Definition(ArgumentResolver::class, [null, []]);\n        $container = new ContainerBuilder();\n        $container->register('debug.stopwatch', Stopwatch::class);\n        $container->setDefinition('argument_resolver', $definition);\n\n        foreach ($services as $id => [$tag]) {\n            $container->register($id)->addTag('controller.argument_value_resolver', $tag);\n        }\n\n        $container->setParameter('kernel.debug', true);\n\n        (new ControllerArgumentValueResolverPass())->process($container);\n        $this->assertEquals($expected, $definition->getArgument(1)->getValues());\n\n        $this->assertTrue($container->hasDefinition('.debug.value_resolver.n1'));\n        $this->assertTrue($container->hasDefinition('.debug.value_resolver.n2'));\n        $this->assertTrue($container->hasDefinition('.debug.value_resolver.n3'));\n\n        $this->assertTrue($container->hasDefinition('n1'));\n        $this->assertTrue($container->hasDefinition('n2'));\n        $this->assertTrue($container->hasDefinition('n3'));\n    }\n\n    public function testInDebugWithouStopWatchDefinition()\n    {\n        $expected = [new Reference('n1')];\n\n        $definition = new Definition(ArgumentResolver::class, [null, []]);\n        $container = new ContainerBuilder();\n        $container->register('n1')->addTag('controller.argument_value_resolver');\n        $container->setDefinition('argument_resolver', $definition);\n\n        $container->setParameter('kernel.debug', true);\n\n        (new ControllerArgumentValueResolverPass())->process($container);\n        $this->assertEquals($expected, $definition->getArgument(1)->getValues());\n\n        $this->assertFalse($container->hasDefinition('debug.n1'));\n        $this->assertTrue($container->hasDefinition('n1'));\n    }\n\n    public function testReturningEmptyArrayWhenNoService()\n    {\n        $definition = new Definition(ArgumentResolver::class, [null, []]);\n        $container = new ContainerBuilder();\n        $container->setDefinition('argument_resolver', $definition);\n\n        $container->setParameter('kernel.debug', false);\n\n        (new ControllerArgumentValueResolverPass())->process($container);\n        $this->assertEquals([], $definition->getArgument(1)->getValues());\n    }\n\n    public function testNoArgumentResolver()\n    {\n        $container = new ContainerBuilder();\n\n        (new ControllerArgumentValueResolverPass())->process($container);\n\n        $this->assertFalse($container->hasDefinition('argument_resolver'));\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/ControllerAttributesListenerPassTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DependencyInjection;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Definition;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\HttpKernel\\DependencyInjection\\ControllerAttributesListenerPass;\nuse Symfony\\Component\\HttpKernel\\EventListener\\ControllerAttributesListener;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\n\nclass ControllerAttributesListenerPassTest extends TestCase\n{\n    public function testCollectsAttributeListenersByKernelEvent()\n    {\n        $container = new ContainerBuilder();\n\n        $dispatcher = new Definition();\n        $dispatcher->addMethodCall('addListener', [KernelEvents::CONTROLLER.'.'.TestAttribute::class, [new Reference('listener.service'), 'onKernelController'], 0]);\n        $dispatcher->addMethodCall('addListener', [KernelEvents::RESPONSE.'.'.AnotherAttribute::class, [new Reference('listener.service'), 'onKernelResponse'], 0]);\n        $dispatcher->addMethodCall('addListener', [KernelEvents::REQUEST, [new Reference('other.service'), 'onKernelRequest'], 0]);\n        $container->setDefinition('event_dispatcher', $dispatcher);\n\n        $listener = new Definition(ControllerAttributesListener::class, [[]]);\n        $container->setDefinition('kernel.controller_attributes_listener', $listener);\n\n        $pass = new ControllerAttributesListenerPass();\n        $pass->process($container);\n\n        $this->assertSame([\n            KernelEvents::CONTROLLER => [TestAttribute::class => true],\n            KernelEvents::RESPONSE => [AnotherAttribute::class => true],\n        ], $listener->getArgument(0));\n    }\n\n    public function testSetsEmptyConfigurationWhenNoAttributeListenersAreRegistered()\n    {\n        $container = new ContainerBuilder();\n\n        $dispatcher = new Definition();\n        $dispatcher->addMethodCall('addListener', [KernelEvents::REQUEST, [new Reference('listener.service'), 'onKernelRequest'], 0]);\n        $container->setDefinition('event_dispatcher', $dispatcher);\n\n        $listener = new Definition(ControllerAttributesListener::class, [[]]);\n        $container->setDefinition('kernel.controller_attributes_listener', $listener);\n\n        $pass = new ControllerAttributesListenerPass();\n        $pass->process($container);\n\n        $this->assertSame([], $listener->getArgument(0));\n    }\n}\n\n#[\\Attribute]\nclass TestAttribute\n{\n}\n\n#[\\Attribute]\nclass AnotherAttribute extends TestAttribute\n{\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/FragmentRendererPassTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DependencyInjection;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\DependencyInjection\\Argument\\ServiceClosureArgument;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\DependencyInjection\\ServiceLocator;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\DependencyInjection\\FragmentRendererPass;\nuse Symfony\\Component\\HttpKernel\\Fragment\\FragmentRendererInterface;\n\nclass FragmentRendererPassTest extends TestCase\n{\n    /**\n     * Tests that content rendering not implementing FragmentRendererInterface\n     * triggers an exception.\n     */\n    public function testContentRendererWithoutInterface()\n    {\n        $this->expectException(\\InvalidArgumentException::class);\n        $builder = new ContainerBuilder();\n        $fragmentHandlerDefinition = $builder->register('fragment.handler');\n        $builder->register('my_content_renderer', 'Symfony\\Component\\DependencyInjection\\Definition')\n            ->addTag('kernel.fragment_renderer', ['alias' => 'foo']);\n\n        $pass = new FragmentRendererPass();\n        $pass->process($builder);\n\n        $this->assertEquals([['addRendererService', ['foo', 'my_content_renderer']]], $fragmentHandlerDefinition->getMethodCalls());\n    }\n\n    public function testValidContentRenderer()\n    {\n        $builder = new ContainerBuilder();\n        $fragmentHandlerDefinition = $builder->register('fragment.handler')\n            ->addArgument(null);\n        $builder->register('my_content_renderer', 'Symfony\\Component\\HttpKernel\\Tests\\DependencyInjection\\RendererService')\n            ->addTag('kernel.fragment_renderer', ['alias' => 'foo']);\n\n        $pass = new FragmentRendererPass();\n        $pass->process($builder);\n\n        $serviceLocatorDefinition = $builder->getDefinition((string) $fragmentHandlerDefinition->getArgument(0));\n        $this->assertSame(ServiceLocator::class, $serviceLocatorDefinition->getClass());\n        $this->assertEquals(['foo' => new ServiceClosureArgument(new Reference('my_content_renderer'))], $serviceLocatorDefinition->getArgument(0));\n    }\n}\n\nclass RendererService implements FragmentRendererInterface\n{\n    public function render($uri, ?Request $request = null, array $options = []): Response\n    {\n    }\n\n    public function getName(): string\n    {\n        return 'test';\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/LazyLoadingFragmentHandlerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DependencyInjection;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\DependencyInjection\\Container;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\DependencyInjection\\LazyLoadingFragmentHandler;\nuse Symfony\\Component\\HttpKernel\\Fragment\\FragmentRendererInterface;\n\nclass LazyLoadingFragmentHandlerTest extends TestCase\n{\n    public function testRender()\n    {\n        $renderer = $this->createMock(FragmentRendererInterface::class);\n        $renderer->expects($this->once())->method('getName')->willReturn('foo');\n        $renderer->method('render')->willReturn(new Response());\n\n        $requestStack = new RequestStack();\n        $requestStack->push(Request::create('/'));\n\n        $container = new Container();\n        $container->set('foo', $renderer);\n\n        $handler = new LazyLoadingFragmentHandler($container, $requestStack, false);\n\n        $handler->render('/foo', 'foo');\n\n        // second call should not lazy-load anymore (see once() above on the get() method)\n        $handler->render('/foo', 'foo');\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/LoggerPassTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DependencyInjection;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\HttpKernel\\DependencyInjection\\LoggerPass;\nuse Symfony\\Component\\HttpKernel\\Log\\Logger;\n\n/**\n * @author Kévin Dunglas <dunglas@gmail.com>\n */\nclass LoggerPassTest extends TestCase\n{\n    public function testAlwaysSetAutowiringAlias()\n    {\n        $container = new ContainerBuilder();\n        $container->register('logger', 'Foo');\n\n        (new LoggerPass())->process($container);\n\n        $this->assertFalse($container->getAlias(LoggerInterface::class)->isPublic());\n    }\n\n    public function testDoNotOverrideExistingLogger()\n    {\n        $container = new ContainerBuilder();\n        $container->register('logger', 'Foo');\n\n        (new LoggerPass())->process($container);\n\n        $this->assertSame('Foo', $container->getDefinition('logger')->getClass());\n    }\n\n    public function testRegisterLogger()\n    {\n        $container = new ContainerBuilder();\n        $container->setParameter('kernel.debug', false);\n\n        (new LoggerPass())->process($container);\n\n        $definition = $container->getDefinition('logger');\n        $this->assertSame(Logger::class, $definition->getClass());\n        $this->assertFalse($definition->isPublic());\n    }\n\n    public function testAutowiringAliasIsPreserved()\n    {\n        $container = new ContainerBuilder();\n        $container->setParameter('kernel.debug', false);\n        $container->setAlias(LoggerInterface::class, 'my_logger');\n\n        (new LoggerPass())->process($container);\n\n        $this->assertSame('my_logger', (string) $container->getAlias(LoggerInterface::class));\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/MergeExtensionConfigurationPassTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DependencyInjection;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Extension\\Extension;\nuse Symfony\\Component\\DependencyInjection\\ParameterBag\\ParameterBag;\nuse Symfony\\Component\\HttpKernel\\DependencyInjection\\MergeExtensionConfigurationPass;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\AcmeFooBundle\\AcmeFooBundle;\n\nclass MergeExtensionConfigurationPassTest extends TestCase\n{\n    public function testAutoloadMainExtension()\n    {\n        $container = new ContainerBuilder();\n        $container->registerExtension(new LoadedExtension());\n        $container->registerExtension(new NotLoadedExtension());\n        $container->loadFromExtension('loaded', []);\n\n        $configPass = new MergeExtensionConfigurationPass(['loaded', 'not_loaded']);\n        $configPass->process($container);\n\n        $this->assertTrue($container->hasDefinition('loaded.foo'));\n        $this->assertTrue($container->hasDefinition('not_loaded.bar'));\n    }\n\n    public function testFooBundle()\n    {\n        $bundle = new AcmeFooBundle();\n\n        $container = new ContainerBuilder(new ParameterBag([\n            'kernel.environment' => 'test',\n            'kernel.build_dir' => sys_get_temp_dir(),\n        ]));\n        $container->registerExtension(new LoadedExtension());\n        $container->registerExtension($bundle->getContainerExtension());\n\n        $configPass = new MergeExtensionConfigurationPass(['loaded', 'acme_foo']);\n        $configPass->process($container);\n\n        $this->assertSame([['bar' => 'baz'], []], $container->getExtensionConfig('loaded'), '->prependExtension() prepends an extension config');\n        $this->assertTrue($container->hasDefinition('acme_foo.foo'), '->loadExtension() registers a service');\n        $this->assertTrue($container->hasDefinition('acme_foo.bar'), '->loadExtension() imports a service');\n        $this->assertTrue($container->hasParameter('acme_foo.config'), '->loadExtension() sets a parameter');\n        $this->assertSame(['foo' => 'bar', 'ping' => 'pong'], $container->getParameter('acme_foo.config'), '->loadConfiguration() defines and loads configurations');\n    }\n}\n\nclass LoadedExtension extends Extension\n{\n    public function load(array $configs, ContainerBuilder $container): void\n    {\n        $container->register('loaded.foo');\n    }\n}\n\nclass NotLoadedExtension extends Extension\n{\n    public function load(array $configs, ContainerBuilder $container): void\n    {\n        $container->register('not_loaded.bar');\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DependencyInjection;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\DependencyInjection\\Argument\\LazyClosure;\nuse Symfony\\Component\\DependencyInjection\\Argument\\RewindableGenerator;\nuse Symfony\\Component\\DependencyInjection\\Argument\\ServiceClosureArgument;\nuse Symfony\\Component\\DependencyInjection\\Attribute\\Autowire;\nuse Symfony\\Component\\DependencyInjection\\Attribute\\AutowireCallable;\nuse Symfony\\Component\\DependencyInjection\\Attribute\\AutowireIterator;\nuse Symfony\\Component\\DependencyInjection\\Attribute\\AutowireLocator;\nuse Symfony\\Component\\DependencyInjection\\Attribute\\Target;\nuse Symfony\\Component\\DependencyInjection\\ChildDefinition;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\ContainerInterface;\nuse Symfony\\Component\\DependencyInjection\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\DependencyInjection\\ServiceLocator;\nuse Symfony\\Component\\DependencyInjection\\TypedReference;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\DependencyInjection\\RegisterControllerArgumentLocatorsPass;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\DataCollector\\DummyController;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Suit;\n\nclass RegisterControllerArgumentLocatorsPassTest extends TestCase\n{\n    public function testInvalidClass()\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage('Class \"Symfony\\Component\\HttpKernel\\Tests\\DependencyInjection\\NotFound\" used for service \"foo\" cannot be found.');\n        $container = new ContainerBuilder();\n        $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', NotFound::class)\n            ->addTag('controller.service_arguments')\n        ;\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n    }\n\n    public function testNoAction()\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage('Missing \"action\" attribute on tag \"controller.service_arguments\" {\"argument\":\"bar\"} for service \"foo\".');\n        $container = new ContainerBuilder();\n        $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', RegisterTestController::class)\n            ->addTag('controller.service_arguments', ['argument' => 'bar'])\n        ;\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n    }\n\n    public function testNoArgument()\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage('Missing \"argument\" attribute on tag \"controller.service_arguments\" {\"action\":\"fooAction\"} for service \"foo\".');\n        $container = new ContainerBuilder();\n        $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', RegisterTestController::class)\n            ->addTag('controller.service_arguments', ['action' => 'fooAction'])\n        ;\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n    }\n\n    public function testNoService()\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage('Missing \"id\" attribute on tag \"controller.service_arguments\" {\"action\":\"fooAction\",\"argument\":\"bar\"} for service \"foo\".');\n        $container = new ContainerBuilder();\n        $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', RegisterTestController::class)\n            ->addTag('controller.service_arguments', ['action' => 'fooAction', 'argument' => 'bar'])\n        ;\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n    }\n\n    public function testInvalidMethod()\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage('Invalid \"action\" attribute on tag \"controller.service_arguments\" for service \"foo\": no public \"barAction()\" method found on class \"Symfony\\Component\\HttpKernel\\Tests\\DependencyInjection\\RegisterTestController\".');\n        $container = new ContainerBuilder();\n        $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', RegisterTestController::class)\n            ->addTag('controller.service_arguments', ['action' => 'barAction', 'argument' => 'bar', 'id' => 'bar_service'])\n        ;\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n    }\n\n    public function testInvalidArgument()\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage('Invalid \"controller.service_arguments\" tag for service \"foo\": method \"fooAction()\" has no \"baz\" argument on class \"Symfony\\Component\\HttpKernel\\Tests\\DependencyInjection\\RegisterTestController\".');\n        $container = new ContainerBuilder();\n        $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', RegisterTestController::class)\n            ->addTag('controller.service_arguments', ['action' => 'fooAction', 'argument' => 'baz', 'id' => 'bar'])\n        ;\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n    }\n\n    public function testAllActions()\n    {\n        $container = new ContainerBuilder();\n        $resolver = $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', RegisterTestController::class)\n            ->addTag('controller.service_arguments')\n        ;\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n\n        $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);\n\n        $this->assertEquals(['foo::fooAction'], array_keys($locator));\n        $this->assertInstanceof(ServiceClosureArgument::class, $locator['foo::fooAction']);\n\n        $locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]);\n        $locator = $container->getDefinition((string) $locator->getFactory()[0]);\n\n        $this->assertSame(ServiceLocator::class, $locator->getClass());\n        $this->assertFalse($locator->isPublic());\n\n        $expected = ['bar' => new ServiceClosureArgument(new TypedReference(ControllerDummy::class, ControllerDummy::class, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE, 'bar'))];\n        $this->assertEquals($expected, $locator->getArgument(0));\n    }\n\n    public function testExplicitArgument()\n    {\n        $container = new ContainerBuilder();\n        $resolver = $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', RegisterTestController::class)\n            ->addTag('controller.service_arguments', ['action' => 'fooAction', 'argument' => 'bar', 'id' => 'bar'])\n            ->addTag('controller.service_arguments', ['action' => 'fooAction', 'argument' => 'bar', 'id' => 'baz']) // should be ignored, the first wins\n        ;\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n\n        $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);\n        $locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]);\n        $locator = $container->getDefinition((string) $locator->getFactory()[0]);\n\n        $expected = ['bar' => new ServiceClosureArgument(new TypedReference('bar', ControllerDummy::class, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE))];\n        $this->assertEquals($expected, $locator->getArgument(0));\n    }\n\n    public function testOptionalArgument()\n    {\n        $container = new ContainerBuilder();\n        $resolver = $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', RegisterTestController::class)\n            ->addTag('controller.service_arguments', ['action' => 'fooAction', 'argument' => 'bar', 'id' => '?bar'])\n        ;\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n\n        $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);\n        $locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]);\n        $locator = $container->getDefinition((string) $locator->getFactory()[0]);\n\n        $expected = ['bar' => new ServiceClosureArgument(new TypedReference('bar', ControllerDummy::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE))];\n        $this->assertEquals($expected, $locator->getArgument(0));\n    }\n\n    public function testSkipSetContainer()\n    {\n        $container = new ContainerBuilder();\n        $resolver = $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', ContainerAwareRegisterTestController::class)\n            ->addTag('controller.service_arguments');\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n\n        $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);\n        $this->assertSame(['foo::fooAction'], array_keys($locator));\n    }\n\n    public function testExceptionOnNonExistentTypeHint()\n    {\n        $this->expectException(\\RuntimeException::class);\n        $this->expectExceptionMessage('Cannot determine controller argument for \"Symfony\\Component\\HttpKernel\\Tests\\DependencyInjection\\NonExistentClassController::fooAction()\": the $nonExistent argument is type-hinted with the non-existent class or interface: \"Symfony\\Component\\HttpKernel\\Tests\\DependencyInjection\\NonExistentClass\". Did you forget to add a use statement?');\n        $container = new ContainerBuilder();\n        $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', NonExistentClassController::class)\n            ->addTag('controller.service_arguments');\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n\n        $error = $container->getDefinition('argument_resolver.service')->getArgument(0);\n        $error = $container->getDefinition($error)->getArgument(0)['foo::fooAction']->getValues()[0];\n        $error = $container->getDefinition($error)->getArgument(0)['nonExistent']->getValues()[0];\n\n        $container->get($error);\n    }\n\n    public function testExceptionOnNonExistentTypeHintDifferentNamespace()\n    {\n        $this->expectException(\\RuntimeException::class);\n        $this->expectExceptionMessage('Cannot determine controller argument for \"Symfony\\Component\\HttpKernel\\Tests\\DependencyInjection\\NonExistentClassDifferentNamespaceController::fooAction()\": the $nonExistent argument is type-hinted with the non-existent class or interface: \"Acme\\NonExistentClass\".');\n        $container = new ContainerBuilder();\n        $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', NonExistentClassDifferentNamespaceController::class)\n            ->addTag('controller.service_arguments');\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n\n        $error = $container->getDefinition('argument_resolver.service')->getArgument(0);\n        $error = $container->getDefinition($error)->getArgument(0)['foo::fooAction']->getValues()[0];\n        $error = $container->getDefinition($error)->getArgument(0)['nonExistent']->getValues()[0];\n\n        $container->get($error);\n    }\n\n    public function testNoExceptionOnNonExistentTypeHintOptionalArg()\n    {\n        $container = new ContainerBuilder();\n        $resolver = $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', NonExistentClassOptionalController::class)\n            ->addTag('controller.service_arguments');\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n\n        $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);\n\n        $this->assertEqualsCanonicalizing(['foo::barAction', 'foo::fooAction'], array_keys($locator));\n    }\n\n    public function testArgumentWithNoTypeHintIsOk()\n    {\n        $container = new ContainerBuilder();\n        $resolver = $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', ArgumentWithoutTypeController::class)\n            ->addTag('controller.service_arguments');\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n\n        $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);\n        $this->assertSame([], array_keys($locator));\n    }\n\n    public function testControllersAreMadePublic()\n    {\n        $container = new ContainerBuilder();\n        $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', ArgumentWithoutTypeController::class)\n            ->addTag('controller.service_arguments');\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n\n        $this->assertTrue($container->getDefinition('foo')->isPublic());\n    }\n\n    public function testControllersAreMadeNonLazy()\n    {\n        $container = new ContainerBuilder();\n        $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', DummyController::class)\n            ->addTag('controller.service_arguments')\n            ->setLazy(true);\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n\n        $this->assertFalse($container->getDefinition('foo')->isLazy());\n    }\n\n    #[DataProvider('provideBindings')]\n    public function testBindings($bindingName)\n    {\n        $container = new ContainerBuilder();\n        $resolver = $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', RegisterTestController::class)\n            ->setBindings([$bindingName => new Reference('foo')])\n            ->addTag('controller.service_arguments');\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n\n        $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);\n        $locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]);\n        $locator = $container->getDefinition((string) $locator->getFactory()[0]);\n\n        $expected = ['bar' => new ServiceClosureArgument(new Reference('foo'))];\n        $this->assertEquals($expected, $locator->getArgument(0));\n    }\n\n    public static function provideBindings()\n    {\n        return [\n            [ControllerDummy::class.'$bar'],\n            [ControllerDummy::class],\n            ['$bar'],\n        ];\n    }\n\n    #[DataProvider('provideBindScalarValueToControllerArgument')]\n    public function testBindScalarValueToControllerArgument($bindingKey)\n    {\n        $container = new ContainerBuilder();\n        $resolver = $container->register('argument_resolver.service', 'stdClass')->addArgument([]);\n\n        $container->register('foo', ArgumentWithoutTypeController::class)\n            ->setBindings([$bindingKey => '%foo%'])\n            ->addTag('controller.service_arguments');\n\n        $container->setParameter('foo', 'foo_val');\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n\n        $locatorId = (string) $resolver->getArgument(0);\n        $container->getDefinition($locatorId)->setPublic(true);\n\n        $container->compile();\n\n        $locator = $container->get($locatorId);\n        $this->assertSame('foo_val', $locator->get('foo::fooAction')->get('someArg'));\n    }\n\n    public static function provideBindScalarValueToControllerArgument()\n    {\n        yield ['$someArg'];\n        yield ['string $someArg'];\n    }\n\n    public function testBindingsOnChildDefinitions()\n    {\n        $container = new ContainerBuilder();\n        $resolver = $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('parent', ArgumentWithoutTypeController::class);\n\n        $container->setDefinition('child', (new ChildDefinition('parent'))\n            ->setBindings(['$someArg' => new Reference('parent')])\n            ->addTag('controller.service_arguments')\n        );\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n\n        $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);\n        $this->assertInstanceOf(ServiceClosureArgument::class, $locator['child::fooAction']);\n\n        $locator = $container->getDefinition((string) $locator['child::fooAction']->getValues()[0]);\n        $locator = $container->getDefinition((string) $locator->getFactory()[0])->getArgument(0);\n        $this->assertInstanceOf(ServiceClosureArgument::class, $locator['someArg']);\n        $this->assertEquals(new Reference('parent'), $locator['someArg']->getValues()[0]);\n    }\n\n    public function testNotTaggedControllerServiceReceivesLocatorArgument()\n    {\n        $container = new ContainerBuilder();\n        $container->register('argument_resolver.not_tagged_controller')->addArgument([]);\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n\n        $locatorArgument = $container->getDefinition('argument_resolver.not_tagged_controller')->getArgument(0);\n\n        $this->assertInstanceOf(Reference::class, $locatorArgument);\n    }\n\n    public function testAlias()\n    {\n        $container = new ContainerBuilder();\n        $resolver = $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', RegisterTestController::class)\n            ->addTag('controller.service_arguments');\n\n        $container->setAlias(RegisterTestController::class, 'foo')->setPublic(true);\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n\n        $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);\n        $this->assertEqualsCanonicalizing([RegisterTestController::class.'::fooAction', 'foo::fooAction'], array_keys($locator));\n    }\n\n    public function testEnumArgumentIsIgnored()\n    {\n        $container = new ContainerBuilder();\n        $resolver = $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('foo', NonNullableEnumArgumentWithDefaultController::class)\n            ->addTag('controller.service_arguments')\n        ;\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n\n        $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);\n        $this->assertSame([], array_keys($locator), 'enum typed argument is ignored');\n    }\n\n    public function testBindWithTarget()\n    {\n        $container = new ContainerBuilder();\n        $resolver = $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register(ControllerDummy::class, 'bar');\n        $container->register(ControllerDummy::class.' $imageStorage', 'baz');\n\n        $container->register('foo', WithTarget::class)\n            ->setBindings(['string $someApiKey' => new Reference('the_api_key')])\n            ->addTag('controller.service_arguments');\n\n        (new RegisterControllerArgumentLocatorsPass())->process($container);\n\n        $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);\n        $locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]);\n        $locator = $container->getDefinition((string) $locator->getFactory()[0]);\n\n        $expected = [\n            'apiKey' => new ServiceClosureArgument(new Reference('the_api_key')),\n            'service1' => new ServiceClosureArgument(new TypedReference(ControllerDummy::class, ControllerDummy::class, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE, 'imageStorage', [new Target('image.storage')])),\n            'service2' => new ServiceClosureArgument(new TypedReference(ControllerDummy::class, ControllerDummy::class, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE, 'service2')),\n        ];\n        $this->assertEquals($expected, $locator->getArgument(0));\n    }\n\n    public function testTargetAttributeUsesShortNameForControllerArguments()\n    {\n        $container = new ContainerBuilder();\n        $resolver = $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('limiter.anonymous_action', DummyRateLimiterFactory::class);\n        $container->registerAliasForArgument('limiter.anonymous_action', DummyLimiterFactoryInterface::class, 'anonymous_action.limiter', 'anonymous_action');\n\n        $container->register('foo', WithTargetShortName::class)\n            ->addTag('controller.service_arguments');\n\n        (new RegisterControllerArgumentLocatorsPass())->process($container);\n\n        $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);\n        $locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]);\n        $locator = $container->getDefinition((string) $locator->getFactory()[0]);\n\n        $argument = $locator->getArgument(0)['limiterFactory']->getValues()[0];\n        $this->assertInstanceOf(TypedReference::class, $argument);\n        $this->assertSame(DummyLimiterFactoryInterface::class, $argument->getType());\n        $this->assertSame('anonymous_action', $argument->getName());\n        $this->assertEquals([new Target('anonymous_action')], $argument->getAttributes());\n    }\n\n    public function testResponseArgumentIsIgnored()\n    {\n        $container = new ContainerBuilder();\n        $resolver = $container->register('argument_resolver.service', 'stdClass')->addArgument([]);\n\n        $container->register('foo', WithResponseArgument::class)\n            ->addTag('controller.service_arguments');\n\n        (new RegisterControllerArgumentLocatorsPass())->process($container);\n\n        $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);\n        $this->assertSame([], array_keys($locator), 'Response typed argument is ignored');\n    }\n\n    public function testAutowireAttribute()\n    {\n        $container = new ContainerBuilder();\n        $resolver = $container->register('argument_resolver.service', 'stdClass')->addArgument([]);\n\n        $container->register('some.id', \\stdClass::class)->setPublic(true);\n        $container->setParameter('some.parameter', 'foo');\n\n        $container->register('foo', WithAutowireAttribute::class)\n            ->addTag('controller.service_arguments');\n\n        (new RegisterControllerArgumentLocatorsPass())->process($container);\n\n        $locatorId = (string) $resolver->getArgument(0);\n        $container->getDefinition($locatorId)->setPublic(true);\n\n        $container->compile();\n\n        $locator = $container->get($locatorId)->get('foo::fooAction');\n\n        $this->assertCount(10, $locator->getProvidedServices());\n        $this->assertInstanceOf(\\stdClass::class, $locator->get('service1'));\n        $this->assertSame('foo/bar', $locator->get('value'));\n        $this->assertSame('foo', $locator->get('expression'));\n        $this->assertInstanceOf(\\stdClass::class, $locator->get('serviceAsValue'));\n        $this->assertInstanceOf(\\stdClass::class, $locator->get('expressionAsValue'));\n        $this->assertSame('bar', $locator->get('rawValue'));\n        $this->assertStringContainsString('Symfony_Component_HttpKernel_Tests_Fixtures_Suit_APP_SUIT', $locator->get('suit'));\n        $this->assertSame('@bar', $locator->get('escapedRawValue'));\n        $this->assertSame('foo', $locator->get('customAutowire'));\n        $this->assertInstanceOf(FooInterface::class, $autowireCallable = $locator->get('autowireCallable'));\n        $this->assertInstanceOf(LazyClosure::class, $autowireCallable);\n        $this->assertInstanceOf(\\stdClass::class, $autowireCallable->service);\n        $this->assertFalse($locator->has('service2'));\n    }\n\n    public function testAutowireIteratorAndAutowireLocatorAttributes()\n    {\n        $container = new ContainerBuilder();\n        $container->setParameter('some.parameter', 'bar');\n        $resolver = $container->register('argument_resolver.service', \\stdClass::class)->addArgument([]);\n\n        $container->register('bar', \\stdClass::class)->addTag('foobar');\n        $container->register('baz', \\stdClass::class)->addTag('foobar');\n\n        $container->register('foo', WithAutowireIteratorAndAutowireLocator::class)\n            ->addTag('controller.service_arguments');\n\n        (new RegisterControllerArgumentLocatorsPass())->process($container);\n\n        $locatorId = (string) $resolver->getArgument(0);\n        $container->getDefinition($locatorId)->setPublic(true);\n\n        $container->compile();\n\n        /** @var ServiceLocator $locator */\n        $locator = $container->get($locatorId)->get('foo::fooAction');\n\n        $this->assertCount(4, $locator->getProvidedServices());\n\n        $this->assertTrue($locator->has('iterator1'));\n        $this->assertInstanceOf(RewindableGenerator::class, $argIterator = $locator->get('iterator1'));\n        $this->assertCount(2, $argIterator);\n\n        $this->assertTrue($locator->has('locator1'));\n        $this->assertInstanceOf(ServiceLocator::class, $argLocator = $locator->get('locator1'));\n        $this->assertCount(2, $argLocator);\n        $this->assertTrue($argLocator->has('bar'));\n        $this->assertTrue($argLocator->has('baz'));\n\n        $this->assertSame(iterator_to_array($argIterator), [$argLocator->get('bar'), $argLocator->get('baz')]);\n\n        $this->assertTrue($locator->has('container1'));\n        $this->assertInstanceOf(ServiceLocator::class, $argLocator = $locator->get('container1'));\n        $this->assertCount(2, $argLocator);\n        $this->assertTrue($argLocator->has('bar'));\n        $this->assertTrue($argLocator->has('baz'));\n\n        $this->assertTrue($locator->has('container2'));\n        $this->assertInstanceOf(ServiceLocator::class, $argLocator = $locator->get('container2'));\n        $this->assertCount(1, $argLocator);\n        $this->assertTrue($argLocator->has('foo'));\n        $this->assertSame('bar', $argLocator->get('foo'));\n    }\n\n    public function testTaggedControllersAreRegisteredInControllerResolver()\n    {\n        $container = new ContainerBuilder();\n        $container->register('argument_resolver.service')->addArgument([]);\n        $controllerResolver = $container->register('controller_resolver');\n\n        $container->register('foo', RegisterTestController::class)\n            ->addTag('controller.service_arguments')\n        ;\n\n        // duplicates should be removed\n        $container->register('bar', RegisterTestController::class)\n            ->addTag('controller.service_arguments')\n        ;\n\n        // services with no tag should be ignored\n        $container->register('baz', ControllerDummy::class);\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n\n        $this->assertSame([['allowControllers', [[RegisterTestController::class]]]], $controllerResolver->getMethodCalls());\n    }\n}\n\nclass RegisterTestController\n{\n    public function __construct(ControllerDummy $bar)\n    {\n    }\n\n    public function fooAction(ControllerDummy $bar)\n    {\n    }\n\n    protected function barAction(ControllerDummy $bar)\n    {\n    }\n}\n\nclass ContainerAwareRegisterTestController\n{\n    protected ?ContainerInterface $container;\n\n    public function setContainer(?ContainerInterface $container = null): void\n    {\n        $this->container = $container;\n    }\n\n    public function fooAction(ControllerDummy $bar)\n    {\n    }\n}\n\nclass ControllerDummy\n{\n}\n\nclass NonExistentClassController\n{\n    public function fooAction(NonExistentClass $nonExistent)\n    {\n    }\n}\n\nclass NonExistentClassDifferentNamespaceController\n{\n    public function fooAction(\\Acme\\NonExistentClass $nonExistent)\n    {\n    }\n}\n\nclass NonExistentClassOptionalController\n{\n    public function fooAction(?NonExistentClass $nonExistent = null)\n    {\n    }\n\n    public function barAction(?NonExistentClass $nonExistent, $bar)\n    {\n    }\n}\n\nclass ArgumentWithoutTypeController\n{\n    public function fooAction(string $someArg)\n    {\n    }\n}\n\nclass NonNullableEnumArgumentWithDefaultController\n{\n    public function fooAction(Suit $suit = Suit::Spades)\n    {\n    }\n}\n\nclass WithTarget\n{\n    public function fooAction(\n        #[Target('some.api.key')]\n        string $apiKey,\n        #[Target('image.storage')]\n        ControllerDummy $service1,\n        ControllerDummy $service2,\n    ) {\n    }\n}\n\nclass WithTargetShortName\n{\n    public function fooAction(\n        #[Target('anonymous_action')]\n        DummyLimiterFactoryInterface $limiterFactory,\n    ) {\n    }\n}\n\ninterface DummyLimiterFactoryInterface\n{\n    public function create(mixed $key = null): object;\n}\n\nclass DummyRateLimiterFactory implements DummyLimiterFactoryInterface\n{\n    public function create(mixed $key = null): object\n    {\n        throw new \\BadMethodCallException('Not used in tests.');\n    }\n}\n\nclass WithResponseArgument\n{\n    public function fooAction(Response $response, ?Response $nullableResponse)\n    {\n    }\n}\n\n#[\\Attribute(\\Attribute::TARGET_PARAMETER)]\nclass CustomAutowire extends Autowire\n{\n    public function __construct(string $parameter)\n    {\n        parent::__construct('%'.$parameter.'%');\n    }\n}\n\ninterface FooInterface\n{\n    public function foo();\n}\n\nclass WithAutowireAttribute\n{\n    public function fooAction(\n        #[Autowire(service: 'some.id')]\n        \\stdClass $service1,\n        #[Autowire(value: '%some.parameter%/bar')]\n        string $value,\n        #[Autowire(expression: \"parameter('some.parameter')\")]\n        string $expression,\n        #[Autowire('@some.id')]\n        \\stdClass $serviceAsValue,\n        #[Autowire(\"@=service('some.id')\")]\n        \\stdClass $expressionAsValue,\n        #[Autowire('bar')]\n        string $rawValue,\n        #[Autowire(env: 'enum:\\Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Suit:APP_SUIT')]\n        Suit $suit,\n        #[Autowire('@@bar')]\n        string $escapedRawValue,\n        #[CustomAutowire('some.parameter')]\n        string $customAutowire,\n        #[AutowireCallable(service: 'some.id', method: 'bar')]\n        FooInterface $autowireCallable,\n        #[Autowire(service: 'invalid.id')]\n        ?\\stdClass $service2 = null,\n    ) {\n    }\n}\n\nclass WithAutowireIteratorAndAutowireLocator\n{\n    public function fooAction(\n        #[AutowireIterator('foobar')] iterable $iterator1,\n        #[AutowireLocator('foobar')] ServiceLocator $locator1,\n        #[AutowireLocator(['bar', 'baz'])] ContainerInterface $container1,\n        #[AutowireLocator(['foo' => new Autowire('%some.parameter%')])] ContainerInterface $container2,\n    ) {\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/RegisterLocaleAwareServicesPassTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DependencyInjection;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\DependencyInjection\\Argument\\IteratorArgument;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\HttpKernel\\DependencyInjection\\RegisterLocaleAwareServicesPass;\nuse Symfony\\Component\\HttpKernel\\EventListener\\LocaleAwareListener;\nuse Symfony\\Contracts\\Translation\\LocaleAwareInterface;\n\nclass RegisterLocaleAwareServicesPassTest extends TestCase\n{\n    public function testCompilerPass()\n    {\n        $container = new ContainerBuilder();\n\n        $container->register('locale_aware_listener', LocaleAwareListener::class)\n                  ->setPublic(true)\n                  ->setArguments([null, null]);\n\n        $container->register('some_locale_aware_service', LocaleAwareInterface::class)\n                  ->setPublic(true)\n                  ->addTag('kernel.locale_aware');\n\n        $container->register('another_locale_aware_service', LocaleAwareInterface::class)\n                  ->setPublic(true)\n                  ->addTag('kernel.locale_aware');\n\n        $container->addCompilerPass(new RegisterLocaleAwareServicesPass());\n        $container->compile();\n\n        $this->assertEquals(\n            [\n                new IteratorArgument([\n                    0 => new Reference('some_locale_aware_service'),\n                    1 => new Reference('another_locale_aware_service'),\n                ]),\n                null,\n            ],\n            $container->getDefinition('locale_aware_listener')->getArguments()\n        );\n    }\n\n    public function testListenerUnregisteredWhenNoLocaleAwareServices()\n    {\n        $container = new ContainerBuilder();\n\n        $container->register('locale_aware_listener', LocaleAwareListener::class)\n                  ->setPublic(true)\n                  ->setArguments([null, null]);\n\n        $container->addCompilerPass(new RegisterLocaleAwareServicesPass());\n        $container->compile();\n\n        $this->assertFalse($container->hasDefinition('locale_aware_listener'));\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DependencyInjection;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\DependencyInjection\\Compiler\\ResolveInvalidReferencesPass;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\HttpKernel\\DependencyInjection\\RegisterControllerArgumentLocatorsPass;\nuse Symfony\\Component\\HttpKernel\\DependencyInjection\\RemoveEmptyControllerArgumentLocatorsPass;\n\nclass RemoveEmptyControllerArgumentLocatorsPassTest extends TestCase\n{\n    public function testProcess()\n    {\n        $container = new ContainerBuilder();\n        $resolver = $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('stdClass', 'stdClass');\n        $container->register(TestCase::class, 'stdClass');\n        $container->register('c1', RemoveTestController1::class)->addTag('controller.service_arguments');\n        $container->register('c2', RemoveTestController2::class)->addTag('controller.service_arguments')\n            ->addMethodCall('setTestCase', [new Reference('c1')]);\n\n        $pass = new RegisterControllerArgumentLocatorsPass();\n        $pass->process($container);\n\n        $controllers = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);\n        $getLocator = static fn ($controllers, $k) => $container->getDefinition((string) $container->getDefinition((string) $controllers[$k]->getValues()[0])->getFactory()[0])->getArgument(0);\n\n        $this->assertCount(2, $getLocator($controllers, 'c1::fooAction'));\n        $this->assertCount(1, $getLocator($controllers, 'c2::setTestCase'));\n        $this->assertCount(1, $getLocator($controllers, 'c2::fooAction'));\n\n        (new ResolveInvalidReferencesPass())->process($container);\n\n        $this->assertCount(1, $getLocator($controllers, 'c2::setTestCase'));\n        $this->assertSame([], $getLocator($controllers, 'c2::fooAction'));\n\n        (new RemoveEmptyControllerArgumentLocatorsPass())->process($container);\n\n        $controllers = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);\n\n        $this->assertSame(['c1::fooAction', 'c1:fooAction'], array_keys($controllers));\n        $this->assertSame(['bar'], array_keys($getLocator($controllers, 'c1::fooAction')));\n\n        $expectedLog = [\n            'Symfony\\Component\\HttpKernel\\DependencyInjection\\RemoveEmptyControllerArgumentLocatorsPass: Removing service-argument resolver for controller \"c2::fooAction\": no corresponding services exist for the referenced types.',\n            'Symfony\\Component\\HttpKernel\\DependencyInjection\\RemoveEmptyControllerArgumentLocatorsPass: Removing method \"setTestCase\" of service \"c2\" from controller candidates: the method is called at instantiation, thus cannot be an action.',\n        ];\n\n        $this->assertEqualsCanonicalizing($expectedLog, $container->getCompiler()->getLog());\n    }\n\n    public function testInvoke()\n    {\n        $container = new ContainerBuilder();\n        $resolver = $container->register('argument_resolver.service')->addArgument([]);\n\n        $container->register('invokable', InvokableRegisterTestController::class)\n            ->addTag('controller.service_arguments')\n        ;\n\n        (new RegisterControllerArgumentLocatorsPass())->process($container);\n        (new RemoveEmptyControllerArgumentLocatorsPass())->process($container);\n\n        $this->assertEquals(\n            ['invokable::__invoke', 'invokable:__invoke', 'invokable'],\n            array_keys($container->getDefinition((string) $resolver->getArgument(0))->getArgument(0))\n        );\n    }\n}\n\nclass RemoveTestController1\n{\n    public function fooAction(\\stdClass $bar, ?ClassNotInContainer $baz = null)\n    {\n    }\n}\n\nclass RemoveTestController2\n{\n    public function setTestCase(TestCase $test)\n    {\n    }\n\n    public function fooAction(?ClassNotInContainer $bar = null)\n    {\n    }\n}\n\nclass InvokableRegisterTestController\n{\n    public function __invoke(\\stdClass $bar)\n    {\n    }\n}\n\nclass ClassNotInContainer\n{\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/ResettableServicePassTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DependencyInjection;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\DependencyInjection\\Argument\\IteratorArgument;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\ContainerInterface;\nuse Symfony\\Component\\DependencyInjection\\Exception\\RuntimeException;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\HttpKernel\\DependencyInjection\\ResettableServicePass;\nuse Symfony\\Component\\HttpKernel\\DependencyInjection\\ServicesResetter;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\ClearableService;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\MultiResettableService;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\ResettableService;\n\nclass ResettableServicePassTest extends TestCase\n{\n    public function testCompilerPass()\n    {\n        $container = new ContainerBuilder();\n        $container->register('one', ResettableService::class)\n            ->setPublic(true)\n            ->addTag('kernel.reset', ['method' => 'reset']);\n        $container->register('two', ClearableService::class)\n            ->setPublic(true)\n            ->addTag('kernel.reset', ['method' => 'clear']);\n        $container->register('three', MultiResettableService::class)\n            ->setPublic(true)\n            ->addTag('kernel.reset', ['method' => 'resetFirst'])\n            ->addTag('kernel.reset', ['method' => 'resetSecond']);\n\n        $container->register('services_resetter', ServicesResetter::class)\n            ->setPublic(true)\n            ->setArguments([null, []]);\n        $container->addCompilerPass(new ResettableServicePass());\n\n        $container->compile();\n\n        $definition = $container->getDefinition('services_resetter');\n\n        $this->assertEquals(\n            [\n                new IteratorArgument([\n                    'one' => new Reference('one', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE),\n                    'two' => new Reference('two', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE),\n                    'three' => new Reference('three', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE),\n                ]),\n                [\n                    'one' => ['reset'],\n                    'two' => ['clear'],\n                    'three' => ['resetFirst', 'resetSecond'],\n                ],\n            ],\n            $definition->getArguments()\n        );\n    }\n\n    public function testMissingMethod()\n    {\n        $this->expectException(RuntimeException::class);\n        $this->expectExceptionMessage('Tag \"kernel.reset\" requires the \"method\" attribute to be set on service \"Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\ResettableService\".');\n        $container = new ContainerBuilder();\n        $container->register(ResettableService::class)\n            ->addTag('kernel.reset');\n        $container->register('services_resetter', ServicesResetter::class)\n            ->setArguments([null, []]);\n        $container->addCompilerPass(new ResettableServicePass());\n\n        $container->compile();\n    }\n\n    public function testIgnoreInvalidMethod()\n    {\n        $container = new ContainerBuilder();\n        $container->register(ResettableService::class)\n            ->setPublic(true)\n            ->addTag('kernel.reset', ['method' => 'missingMethod', 'on_invalid' => 'ignore']);\n        $container->register('services_resetter', ServicesResetter::class)\n            ->setPublic(true)\n            ->setArguments([null, []]);\n        $container->addCompilerPass(new ResettableServicePass());\n\n        $container->compile();\n\n        $this->assertSame([ResettableService::class => ['?missingMethod']], $container->getDefinition('services_resetter')->getArgument(1));\n\n        $resettable = $container->get(ResettableService::class);\n        $resetter = $container->get('services_resetter');\n        $resetter->reset();\n    }\n\n    public function testCompilerPassWithoutResetters()\n    {\n        $container = new ContainerBuilder();\n        $container->register('services_resetter', ServicesResetter::class)\n            ->setArguments([null, []]);\n        $container->addCompilerPass(new ResettableServicePass());\n\n        $container->compile();\n\n        $this->assertFalse($container->has('services_resetter'));\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/ServicesResetterTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\DependencyInjection;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpKernel\\DependencyInjection\\ServicesResetter;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\ClearableService;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\LazyResettableService;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\MultiResettableService;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\ResettableService;\nuse Symfony\\Component\\VarExporter\\ProxyHelper;\n\nclass ServicesResetterTest extends TestCase\n{\n    protected function setUp(): void\n    {\n        ResettableService::$counter = 0;\n        ClearableService::$counter = 0;\n        MultiResettableService::$resetFirstCounter = 0;\n        MultiResettableService::$resetSecondCounter = 0;\n    }\n\n    public function testResetServices()\n    {\n        $resetter = new ServicesResetter(new \\ArrayIterator([\n            'id1' => new ResettableService(),\n            'id2' => new ClearableService(),\n            'id3' => new MultiResettableService(),\n        ]), [\n            'id1' => ['reset'],\n            'id2' => ['clear'],\n            'id3' => ['resetFirst', 'resetSecond'],\n        ]);\n\n        $resetter->reset();\n\n        $this->assertSame(1, ResettableService::$counter);\n        $this->assertSame(1, ClearableService::$counter);\n        $this->assertSame(1, MultiResettableService::$resetFirstCounter);\n        $this->assertSame(1, MultiResettableService::$resetSecondCounter);\n    }\n\n    public function testResetLazyServices()\n    {\n        $proxyCode = ProxyHelper::generateLazyProxy(new \\ReflectionClass(LazyResettableService::class));\n        eval('class LazyResettableServiceProxy'.$proxyCode);\n\n        $lazyService = \\LazyResettableServiceProxy::createLazyProxy(static fn (): LazyResettableService => new LazyResettableService());\n\n        $resetter = new ServicesResetter(new \\ArrayIterator([\n            'lazy' => $lazyService,\n        ]), [\n            'lazy' => ['reset'],\n        ]);\n\n        $resetter->reset();\n        $this->assertSame(0, LazyResettableService::$counter);\n\n        $resetter->reset();\n        $this->assertSame(0, LazyResettableService::$counter);\n\n        $this->assertTrue($lazyService->foo());\n\n        $resetter->reset();\n        $this->assertSame(1, LazyResettableService::$counter);\n    }\n}\n"
  },
  {
    "path": "Tests/Event/ControllerArgumentsEventTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Event;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\ExpressionLanguage\\Expression;\nuse Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerEvent;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute\\Bar;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute\\Baz;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller\\AttributeController;\nuse Symfony\\Component\\HttpKernel\\Tests\\TestHttpKernel;\n\nclass ControllerArgumentsEventTest extends TestCase\n{\n    public function testControllerArgumentsEvent()\n    {\n        $event = new ControllerArgumentsEvent(new TestHttpKernel(), static function () {}, ['test'], new Request(), HttpKernelInterface::MAIN_REQUEST);\n        $this->assertSame(['test'], $event->getArguments());\n    }\n\n    public function testSetAttributes()\n    {\n        $controller = static function () {};\n        $event = new ControllerArgumentsEvent(new TestHttpKernel(), $controller, ['test'], new Request(), HttpKernelInterface::MAIN_REQUEST);\n        $event->setController($controller, []);\n\n        $this->assertSame([], $event->getAttributes());\n    }\n\n    public function testGetAttributes()\n    {\n        $controller = new AttributeController();\n        $request = new Request();\n\n        $controllerEvent = new ControllerEvent(new TestHttpKernel(), $controller, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $event = new ControllerArgumentsEvent(new TestHttpKernel(), $controllerEvent, ['test'], new Request(), HttpKernelInterface::MAIN_REQUEST);\n\n        $expected = [\n            Bar::class => [\n                new Bar('class'),\n                new Bar('method'),\n            ],\n            Baz::class => [\n                new Baz(),\n            ],\n        ];\n\n        $this->assertEquals($expected, $event->getAttributes());\n\n        $attributes = [\n            new Bar('class'),\n            new Bar('method'),\n            new Bar('foo'),\n            new Baz(),\n        ];\n        $event->setController($controller, $attributes);\n\n        $grouped = [\n            Bar::class => [\n                new Bar('class'),\n                new Bar('method'),\n                new Bar('foo'),\n            ],\n            Baz::class => [\n                new Baz(),\n            ],\n        ];\n        $this->assertEquals($grouped, $event->getAttributes());\n        $this->assertEquals($attributes, $event->getAttributes('*'));\n        $this->assertSame($controllerEvent->getAttributes(), $event->getAttributes());\n    }\n\n    public function testGetAttributesByClassName()\n    {\n        $controller = new AttributeController();\n        $request = new Request();\n\n        $controllerEvent = new ControllerEvent(new TestHttpKernel(), $controller, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $event = new ControllerArgumentsEvent(new TestHttpKernel(), $controllerEvent, ['test'], new Request(), HttpKernelInterface::MAIN_REQUEST);\n\n        $expected = [\n            new Bar('class'),\n            new Bar('method'),\n        ];\n\n        $this->assertEquals($expected, $event->getAttributes(Bar::class));\n\n        // When setting attributes, provide as flat list\n        $flatAttributes = [\n            new Bar('class'),\n            new Bar('method'),\n            new Bar('foo'),\n        ];\n        $event->setController($controller, $flatAttributes);\n\n        $expectedAfterSet = [\n            new Bar('class'),\n            new Bar('method'),\n            new Bar('foo'),\n        ];\n        $this->assertEquals($expectedAfterSet, $event->getAttributes(Bar::class));\n        $this->assertSame($controllerEvent->getAttributes(Bar::class), $event->getAttributes(Bar::class));\n    }\n\n    public function testEvaluateWithClosureUsesNamedArguments()\n    {\n        $request = new Request();\n        $controller = [new AttributeController(), 'action'];\n        $controllerEvent = new ControllerEvent(new TestHttpKernel(), $controller, $request, HttpKernelInterface::MAIN_REQUEST);\n        $event = new ControllerArgumentsEvent(new TestHttpKernel(), $controllerEvent, ['value'], $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $closure = function (array $args, Request $requestArg, ?object $controllerArg) use ($request): string {\n            $this->assertSame(['baz' => 'value'], $args);\n            $this->assertSame($request, $requestArg);\n            $this->assertInstanceOf(AttributeController::class, $controllerArg);\n\n            return 'ok';\n        };\n\n        $this->assertSame('ok', $event->evaluate($closure, null));\n    }\n\n    public function testEvaluateWithExpressionDelegatesToExpressionLanguage()\n    {\n        $request = new Request();\n        $controller = [new AttributeController(), 'action'];\n        $controllerEvent = new ControllerEvent(new TestHttpKernel(), $controller, $request, HttpKernelInterface::MAIN_REQUEST);\n        $event = new ControllerArgumentsEvent(new TestHttpKernel(), $controllerEvent, ['value'], $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $expressionLanguage = $this->createMock(ExpressionLanguage::class);\n        $expressionLanguage->expects($this->once())\n            ->method('evaluate')\n            ->with(new Expression('args[\"baz\"]'), [\n                'request' => $request,\n                'args' => ['baz' => 'value'],\n                'this' => $controller[0],\n            ])\n            ->willReturn('value');\n\n        $this->assertSame('value', $event->evaluate(new Expression('args[\"baz\"]'), $expressionLanguage));\n    }\n}\n"
  },
  {
    "path": "Tests/Event/ControllerAttributeEventTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Event;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\ExpressionLanguage\\Expression;\nuse Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsMetadata;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerAttributeEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller\\AttributeController;\nuse Symfony\\Component\\HttpKernel\\Tests\\TestHttpKernel;\n\nclass ControllerAttributeEventTest extends TestCase\n{\n    public function testEvaluateReturnsValueForNonExpressionOrClosure()\n    {\n        $controllerEvent = new ControllerEvent(new TestHttpKernel(), static function () {}, new Request(), HttpKernelInterface::MAIN_REQUEST);\n        $event = new ControllerAttributeEvent(new \\stdClass(), $controllerEvent);\n\n        $this->assertSame('value', $event->evaluate('value'));\n    }\n\n    public function testEvaluateDelegatesToControllerEvent()\n    {\n        $request = new Request();\n        $controller = [new AttributeController(), 'action'];\n        $controllerEvent = new ControllerEvent(new TestHttpKernel(), $controller, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $expressionLanguage = $this->createMock(ExpressionLanguage::class);\n        $expressionLanguage->expects($this->once())\n            ->method('evaluate')\n            ->with(new Expression('request'), [\n                'request' => $request,\n                'args' => [],\n                'this' => $controller[0],\n            ])\n            ->willReturn($request);\n\n        $event = new ControllerAttributeEvent(new \\stdClass(), $controllerEvent, $expressionLanguage);\n\n        $this->assertSame($request, $event->evaluate(new Expression('request')));\n    }\n\n    public function testEvaluateDelegatesToControllerArgumentsEvent()\n    {\n        $request = new Request();\n        $controller = [new AttributeController(), 'action'];\n        $controllerEvent = new ControllerEvent(new TestHttpKernel(), $controller, $request, HttpKernelInterface::MAIN_REQUEST);\n        $argumentsEvent = new ControllerArgumentsEvent(new TestHttpKernel(), $controllerEvent, ['value'], $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $expressionLanguage = $this->createMock(ExpressionLanguage::class);\n        $expressionLanguage->expects($this->once())\n            ->method('evaluate')\n            ->with(new Expression('args[\"baz\"]'), [\n                'request' => $request,\n                'args' => ['baz' => 'value'],\n                'this' => $controller[0],\n            ])\n            ->willReturn('value');\n\n        $event = new ControllerAttributeEvent(new \\stdClass(), $argumentsEvent, $expressionLanguage);\n\n        $this->assertSame('value', $event->evaluate(new Expression('args[\"baz\"]')));\n    }\n\n    public function testEvaluateDelegatesToControllerMetadata()\n    {\n        $request = new Request();\n        $controller = [new AttributeController(), 'action'];\n        $kernel = new TestHttpKernel();\n        $controllerEvent = new ControllerEvent($kernel, $controller, $request, HttpKernelInterface::MAIN_REQUEST);\n        $argumentsEvent = new ControllerArgumentsEvent($kernel, $controllerEvent, ['value'], $request, HttpKernelInterface::MAIN_REQUEST);\n        $metadata = new ControllerArgumentsMetadata($controllerEvent, $argumentsEvent);\n        $responseEvent = new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, new Response(), $metadata);\n\n        $expressionLanguage = $this->createMock(ExpressionLanguage::class);\n        $expressionLanguage->expects($this->once())\n            ->method('evaluate')\n            ->with(new Expression('args[\"baz\"]'), [\n                'request' => $request,\n                'args' => ['baz' => 'value'],\n                'this' => $controller[0],\n            ])\n            ->willReturn('value');\n\n        $event = new ControllerAttributeEvent(new \\stdClass(), $responseEvent, $expressionLanguage);\n\n        $this->assertSame('value', $event->evaluate(new Expression('args[\"baz\"]')));\n    }\n}\n"
  },
  {
    "path": "Tests/Event/ControllerEventTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Event;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\Attributes\\Group;\nuse PHPUnit\\Framework\\Attributes\\IgnoreDeprecations;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\ExpressionLanguage\\Expression;\nuse Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerEvent;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute\\Bar;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute\\Baz;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller\\AttributeController;\nuse Symfony\\Component\\HttpKernel\\Tests\\TestHttpKernel;\n\nclass ControllerEventTest extends TestCase\n{\n    #[DataProvider('provideGetAttributes')]\n    public function testGetAttributes(callable $controller)\n    {\n        $event = new ControllerEvent(new TestHttpKernel(), $controller, new Request(), HttpKernelInterface::MAIN_REQUEST);\n\n        $expected = [\n            Bar::class => [\n                new Bar('class'),\n                new Bar('method'),\n            ],\n            Baz::class => [\n                new Baz(),\n            ],\n        ];\n\n        $this->assertEquals($expected, $event->getAttributes());\n    }\n\n    #[DataProvider('provideGetAttributes')]\n    public function testGetAttributesByClassName(callable $controller)\n    {\n        $event = new ControllerEvent(new TestHttpKernel(), $controller, new Request(), HttpKernelInterface::MAIN_REQUEST);\n\n        $expected = [\n            new Bar('class'),\n            new Bar('method'),\n        ];\n\n        $this->assertEquals($expected, $event->getAttributes(Bar::class));\n    }\n\n    #[DataProvider('provideGetAttributes')]\n    public function testGetAttributesByInvalidClassName(callable $controller)\n    {\n        $event = new ControllerEvent(new TestHttpKernel(), $controller, new Request(), HttpKernelInterface::MAIN_REQUEST);\n\n        $this->assertEquals([], $event->getAttributes(\\stdClass::class));\n    }\n\n    public function testControllerAttributesAreStoredInRequestAttributes()\n    {\n        $request = new Request();\n        $controller = [new AttributeController(), '__invoke'];\n        $event = new ControllerEvent(new TestHttpKernel(), $controller, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        // Initially, no controller attributes should be in request\n        $this->assertFalse($request->attributes->has('_controller_attributes'));\n\n        // After calling getAttributes(), they should be stored in request attributes\n        $attributes = $event->getAttributes();\n\n        $this->assertTrue($request->attributes->has('_controller_attributes'));\n        $stored = $request->attributes->get('_controller_attributes');\n        $this->assertIsArray($stored);\n        $this->assertCount(3, $stored);\n        $this->assertIsArray($attributes);\n        $this->assertArrayHasKey(Bar::class, $attributes);\n    }\n\n    public function testSetControllerWithAttributesStoresInRequest()\n    {\n        $request = new Request();\n        $controller = [new AttributeController(), '__invoke'];\n        $event = new ControllerEvent(new TestHttpKernel(), $controller, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        // Provide attributes as flat list\n        $customAttributes = [new Bar('custom')];\n\n        $event->setController($controller, $customAttributes);\n\n        $stored = $request->attributes->get('_controller_attributes');\n        $this->assertIsArray($stored);\n        $this->assertCount(1, $stored);\n        $this->assertInstanceOf(Bar::class, $stored[0]);\n    }\n\n    #[IgnoreDeprecations]\n    #[Group('legacy')]\n    public function testSetControllerWithGroupedAttributesConvertsToFlat()\n    {\n        $request = new Request();\n        $controller = [new AttributeController(), '__invoke'];\n        $event = new ControllerEvent(new TestHttpKernel(), $controller, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $groupedAttributes = [Bar::class => [new Bar('custom')]];\n\n        $event->setController($controller, $groupedAttributes);\n\n        $stored = $request->attributes->get('_controller_attributes');\n        $this->assertIsArray($stored);\n        $this->assertCount(1, $stored);\n        $this->assertInstanceOf(Bar::class, $stored[0]);\n    }\n\n    public function testSetControllerWithoutAttributesRemovesFromRequestWhenControllerChanges()\n    {\n        $request = new Request();\n        $controller1 = [new AttributeController(), '__invoke'];\n        $controller2 = static fn () => new Response('test');\n        $event = new ControllerEvent(new TestHttpKernel(), $controller1, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        // First set some attributes\n        $customAttributes = [new Bar('custom')];\n        $event->setController($controller1, $customAttributes);\n        $this->assertEquals($customAttributes, $request->attributes->get('_controller_attributes'));\n\n        // Then set different controller without attributes - should remove attributes\n        $event->setController($controller2);\n        $this->assertFalse($request->attributes->has('_controller_attributes'));\n    }\n\n    public static function provideGetAttributes()\n    {\n        yield [[new AttributeController(), '__invoke']];\n        yield [new AttributeController()];\n        yield [(new AttributeController())->__invoke(...)];\n        yield [#[Bar('class'), Bar('method'), Baz] static function () {}];\n    }\n\n    public function testEvaluateWithClosureUsesArgsRequestAndController()\n    {\n        $request = new Request();\n        $controller = [new AttributeController(), 'action'];\n        $event = new ControllerEvent(new TestHttpKernel(), $controller, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $closure = function (array $args, Request $requestArg, ?object $controllerArg): string {\n            $this->assertSame(['baz' => 'value'], $args);\n            $this->assertInstanceOf(Request::class, $requestArg);\n            $this->assertInstanceOf(AttributeController::class, $controllerArg);\n\n            return 'ok';\n        };\n\n        $this->assertSame('ok', $event->evaluate($closure, null, ['baz' => 'value']));\n    }\n\n    public function testEvaluateWithExpressionUsesExpressionLanguage()\n    {\n        $request = new Request();\n        $controller = [new AttributeController(), 'action'];\n        $event = new ControllerEvent(new TestHttpKernel(), $controller, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $expressionLanguage = $this->createMock(ExpressionLanguage::class);\n        $expressionLanguage->expects($this->once())\n            ->method('evaluate')\n            ->with(new Expression('args[\"baz\"]'), [\n                'request' => $request,\n                'args' => ['baz' => 'value'],\n                'this' => $controller[0],\n            ])\n            ->willReturn('value');\n\n        $this->assertSame('value', $event->evaluate(new Expression('args[\"baz\"]'), $expressionLanguage, ['baz' => 'value']));\n    }\n\n    public function testEvaluateWithExpressionRequiresExpressionLanguage()\n    {\n        $event = new ControllerEvent(new TestHttpKernel(), static function () {}, new Request(), HttpKernelInterface::MAIN_REQUEST);\n\n        $this->expectException(\\LogicException::class);\n        $this->expectExceptionMessage('Cannot evaluate Expression for controllers since no ExpressionLanguage service was configured.');\n\n        $event->evaluate(new Expression('args[\"foo\"]'), null, ['foo' => 'bar']);\n    }\n}\n"
  },
  {
    "path": "Tests/Event/ExceptionEventTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Event;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Event\\ExceptionEvent;\nuse Symfony\\Component\\HttpKernel\\Tests\\TestHttpKernel;\n\nclass ExceptionEventTest extends TestCase\n{\n    public function testAllowSuccessfulResponseIsFalseByDefault()\n    {\n        $event = new ExceptionEvent(new TestHttpKernel(), new Request(), 1, new \\Exception());\n\n        $this->assertFalse($event->isAllowingCustomResponseCode());\n    }\n}\n"
  },
  {
    "path": "Tests/EventListener/AddRequestFormatsListenerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\EventListener;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Event\\RequestEvent;\nuse Symfony\\Component\\HttpKernel\\EventListener\\AddRequestFormatsListener;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\n\n/**\n * @author Gildas Quemener <gildas.quemener@gmail.com>\n */\nclass AddRequestFormatsListenerTest extends TestCase\n{\n    private AddRequestFormatsListener $listener;\n\n    protected function setUp(): void\n    {\n        $this->listener = new AddRequestFormatsListener(['csv' => ['text/csv', 'text/plain']]);\n    }\n\n    public function testIsAnEventSubscriber()\n    {\n        $this->assertInstanceOf(EventSubscriberInterface::class, $this->listener);\n    }\n\n    public function testRegisteredEvent()\n    {\n        $this->assertSame(\n            [KernelEvents::REQUEST => ['onKernelRequest', 100]],\n            AddRequestFormatsListener::getSubscribedEvents()\n        );\n    }\n\n    public function testSetAdditionalFormats()\n    {\n        $request = $this->createMock(Request::class);\n        $event = new RequestEvent($this->createStub(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $request->expects($this->once())\n            ->method('setFormat')\n            ->with('csv', ['text/csv', 'text/plain']);\n\n        $this->listener->onKernelRequest($event);\n    }\n}\n"
  },
  {
    "path": "Tests/EventListener/CacheAttributeListenerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\EventListener;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\Attributes\\TestWith;\nuse PHPUnit\\Framework\\MockObject\\Stub;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Attribute\\Cache;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\EventListener\\CacheAttributeListener;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller\\CacheAttributeController;\n\nclass CacheAttributeListenerTest extends TestCase\n{\n    private CacheAttributeListener $listener;\n    private Response $response;\n    private Cache $cache;\n    private Request $request;\n    private ResponseEvent $event;\n\n    protected function setUp(): void\n    {\n        $this->listener = new CacheAttributeListener();\n        $this->response = new Response();\n        $this->cache = new Cache();\n        $this->request = $this->createRequest($this->cache);\n        $this->event = $this->createEventMock($this->request, $this->response);\n    }\n\n    public function testWontReassignResponseWhenResponseIsUnsuccessful()\n    {\n        $response = $this->event->getResponse();\n\n        $this->response->setStatusCode(500);\n\n        $this->listener->onKernelResponse($this->event);\n\n        $this->assertSame($response, $this->event->getResponse());\n    }\n\n    public function testWontReassignResponseWhenNoConfigurationIsPresent()\n    {\n        $response = $this->event->getResponse();\n\n        $this->request->attributes->remove('_cache');\n\n        $this->listener->onKernelResponse($this->event);\n\n        $this->assertSame($response, $this->event->getResponse());\n    }\n\n    public function testResponseIsPublicIfSharedMaxAgeSetAndPublicNotOverridden()\n    {\n        $request = $this->createRequest(new Cache(smaxage: 1));\n\n        $this->listener->onKernelResponse($this->createEventMock($request, $this->response));\n\n        $this->assertTrue($this->response->headers->hasCacheControlDirective('public'));\n        $this->assertFalse($this->response->headers->hasCacheControlDirective('private'));\n    }\n\n    public function testResponseIsPublicIfConfigurationIsPublicTrue()\n    {\n        $request = $this->createRequest(new Cache(public: true));\n\n        $this->listener->onKernelResponse($this->createEventMock($request, $this->response));\n\n        $this->assertTrue($this->response->headers->hasCacheControlDirective('public'));\n        $this->assertFalse($this->response->headers->hasCacheControlDirective('private'));\n    }\n\n    public function testResponseIsPrivateIfConfigurationIsPublicFalse()\n    {\n        $request = $this->createRequest(new Cache(public: false));\n\n        $this->listener->onKernelResponse($this->createEventMock($request, $this->response));\n\n        $this->assertFalse($this->response->headers->hasCacheControlDirective('public'));\n        $this->assertTrue($this->response->headers->hasCacheControlDirective('private'));\n    }\n\n    public function testResponseIsPublicIfConfigurationIsPublicTrueNoStoreFalse()\n    {\n        $request = $this->createRequest(new Cache(public: true, noStore: false));\n\n        $this->listener->onKernelResponse($this->createEventMock($request, $this->response));\n\n        $this->assertTrue($this->response->headers->hasCacheControlDirective('public'));\n        $this->assertFalse($this->response->headers->hasCacheControlDirective('private'));\n        $this->assertFalse($this->response->headers->hasCacheControlDirective('no-store'));\n    }\n\n    public function testResponseKeepPublicIfConfigurationIsPublicTrueNoStoreTrue()\n    {\n        $request = $this->createRequest(new Cache(public: true, noStore: true));\n\n        $this->listener->onKernelResponse($this->createEventMock($request, $this->response));\n\n        $this->assertTrue($this->response->headers->hasCacheControlDirective('public'));\n        $this->assertFalse($this->response->headers->hasCacheControlDirective('private'));\n        $this->assertTrue($this->response->headers->hasCacheControlDirective('no-store'));\n    }\n\n    public function testResponseKeepPrivateNoStoreIfConfigurationIsNoStoreTrue()\n    {\n        $request = $this->createRequest(new Cache(noStore: true));\n\n        $this->listener->onKernelResponse($this->createEventMock($request, $this->response));\n\n        $this->assertFalse($this->response->headers->hasCacheControlDirective('public'));\n        $this->assertTrue($this->response->headers->hasCacheControlDirective('private'));\n        $this->assertTrue($this->response->headers->hasCacheControlDirective('no-store'));\n    }\n\n    public function testResponseIsPublicIfSharedMaxAgeSetAndNoStoreIsTrue()\n    {\n        $request = $this->createRequest(new Cache(smaxage: 1, noStore: true));\n\n        $this->listener->onKernelResponse($this->createEventMock($request, $this->response));\n\n        $this->assertTrue($this->response->headers->hasCacheControlDirective('public'));\n        $this->assertFalse($this->response->headers->hasCacheControlDirective('private'));\n        $this->assertTrue($this->response->headers->hasCacheControlDirective('no-store'));\n    }\n\n    public function testResponseVary()\n    {\n        $vary = ['foobar'];\n        $request = $this->createRequest(new Cache(vary: $vary));\n\n        $this->listener->onKernelResponse($this->createEventMock($request, $this->response));\n        $this->assertTrue($this->response->hasVary());\n        $result = $this->response->getVary();\n        $this->assertSame($vary, $result);\n    }\n\n    public function testResponseVaryWhenVaryNotSet()\n    {\n        $request = $this->createRequest(new Cache());\n        $vary = ['foobar'];\n        $this->response->setVary($vary);\n\n        $this->listener->onKernelResponse($this->createEventMock($request, $this->response));\n        $this->assertTrue($this->response->hasVary());\n        $result = $this->response->getVary();\n        $this->assertNotEmpty($result, 'Existing vary headers should not be removed');\n        $this->assertSame($vary, $result, 'Vary header should not be changed');\n    }\n\n    public function testResponseIsPrivateIfConfigurationIsPublicNotSet()\n    {\n        $request = $this->createRequest(new Cache());\n\n        $this->listener->onKernelResponse($this->createEventMock($request, $this->response));\n\n        $this->assertFalse($this->response->headers->hasCacheControlDirective('public'));\n    }\n\n    public function testAttributeConfigurationsAreSetOnResponse()\n    {\n        $this->assertNull($this->response->getMaxAge());\n        $this->assertNull($this->response->getExpires());\n        $this->assertFalse($this->response->headers->hasCacheControlDirective('s-maxage'));\n        $this->assertFalse($this->response->headers->hasCacheControlDirective('max-stale'));\n        $this->assertFalse($this->response->headers->hasCacheControlDirective('stale-while-revalidate'));\n        $this->assertFalse($this->response->headers->hasCacheControlDirective('stale-if-error'));\n        $this->assertFalse($this->response->headers->hasCacheControlDirective('no-store'));\n\n        $this->request->attributes->set('_cache', [new Cache(\n            expires: 'tomorrow',\n            maxage: '15',\n            smaxage: '15',\n            maxStale: '5',\n            staleWhileRevalidate: '6',\n            staleIfError: '7',\n            noStore: true,\n        )]);\n\n        $this->listener->onKernelResponse($this->event);\n\n        $this->assertSame(15, $this->response->getMaxAge());\n        $this->assertSame('15', $this->response->headers->getCacheControlDirective('s-maxage'));\n        $this->assertSame('5', $this->response->headers->getCacheControlDirective('max-stale'));\n        $this->assertSame('6', $this->response->headers->getCacheControlDirective('stale-while-revalidate'));\n        $this->assertSame('7', $this->response->headers->getCacheControlDirective('stale-if-error'));\n        $this->assertTrue($this->response->headers->hasCacheControlDirective('no-store'));\n        $this->assertInstanceOf(\\DateTimeInterface::class, $this->response->getExpires());\n    }\n\n    public function testCacheMaxAgeSupportsStrtotimeFormat()\n    {\n        $this->request->attributes->set('_cache', [new Cache(\n            maxage: '1 day',\n            smaxage: '1 day',\n            maxStale: '1 day',\n            staleWhileRevalidate: '1 day',\n            staleIfError: '1 day',\n        )]);\n\n        $this->listener->onKernelResponse($this->event);\n\n        $this->assertSame('86400', $this->response->headers->getCacheControlDirective('s-maxage'));\n        $this->assertSame(86400, $this->response->getMaxAge());\n        $this->assertSame('86400', $this->response->headers->getCacheControlDirective('max-stale'));\n        $this->assertSame('86400', $this->response->headers->getCacheControlDirective('stale-if-error'));\n    }\n\n    #[TestWith(['test.getDate()'])]\n    #[TestWith(['date'])]\n    #[TestWith(['args[\"test\"].getDate()'])]\n    #[TestWith(['request.attributes.get(\"date\")'])]\n    public function testLastModifiedNotModifiedResponse(string $expression)\n    {\n        $entity = new TestEntity();\n\n        $request = $this->createRequest(new Cache(lastModified: $expression));\n        $request->attributes->set('date', new \\DateTimeImmutable('Fri, 23 Aug 2013 00:00:00 GMT'));\n        $request->headers->add(['If-Modified-Since' => 'Fri, 23 Aug 2013 00:00:00 GMT']);\n\n        $listener = new CacheAttributeListener();\n        $controllerArgumentsEvent = new ControllerArgumentsEvent($this->getKernel(), static fn (TestEntity $test) => new Response(), [$entity], $request, null);\n\n        $listener->onKernelControllerArguments($controllerArgumentsEvent);\n        $response = $controllerArgumentsEvent->getController()($entity);\n\n        $this->assertSame(304, $response->getStatusCode());\n    }\n\n    #[TestWith(['test.getDate()'])]\n    #[TestWith(['date'])]\n    #[TestWith(['args[\"test\"].getDate()'])]\n    #[TestWith(['request.attributes.get(\"date\")'])]\n    public function testLastModifiedHeader(string $expression)\n    {\n        $entity = new TestEntity();\n\n        $request = $this->createRequest(new Cache(lastModified: $expression));\n        $request->attributes->set('date', new \\DateTimeImmutable('Fri, 23 Aug 2013 00:00:00 GMT'));\n\n        $listener = new CacheAttributeListener();\n        $controllerArgumentsEvent = new ControllerArgumentsEvent($this->getKernel(), static fn (TestEntity $test) => new Response(), [$entity], $request, null);\n        $listener->onKernelControllerArguments($controllerArgumentsEvent);\n\n        $controllerResponse = $controllerArgumentsEvent->getController()($entity);\n        $responseEvent = new ResponseEvent($this->getKernel(), $request, HttpKernelInterface::MAIN_REQUEST, $controllerResponse);\n        $listener->onKernelResponse($responseEvent);\n\n        $response = $responseEvent->getResponse();\n\n        $this->assertSame(200, $response->getStatusCode());\n        $this->assertTrue($response->headers->has('Last-Modified'));\n        $this->assertSame('Fri, 23 Aug 2013 00:00:00 GMT', $response->headers->get('Last-Modified'));\n    }\n\n    #[TestWith(['test.getId()'])]\n    #[TestWith(['id'])]\n    #[TestWith(['args[\"test\"].getId()'])]\n    #[TestWith(['request.attributes.get(\"id\")'])]\n    public function testEtagNotModifiedResponse(string $expression)\n    {\n        $entity = new TestEntity();\n\n        $request = $this->createRequest(new Cache(etag: $expression));\n        $request->attributes->set('id', '12345');\n        $request->headers->add(['If-None-Match' => \\sprintf('\"%s\"', hash('sha256', $entity->getId()))]);\n\n        $listener = new CacheAttributeListener();\n        $controllerArgumentsEvent = new ControllerArgumentsEvent($this->getKernel(), static fn (TestEntity $test) => new Response(), [$entity], $request, null);\n\n        $listener->onKernelControllerArguments($controllerArgumentsEvent);\n        $response = $controllerArgumentsEvent->getController()($entity);\n\n        $this->assertSame(304, $response->getStatusCode());\n    }\n\n    #[TestWith(['test.getId()'])]\n    #[TestWith(['id'])]\n    #[TestWith(['args[\"test\"].getId()'])]\n    #[TestWith(['request.attributes.get(\"id\")'])]\n    public function testEtagHeader(string $expression)\n    {\n        $entity = new TestEntity();\n\n        $request = $this->createRequest(new Cache(etag: $expression));\n        $request->attributes->set('id', '12345');\n\n        $listener = new CacheAttributeListener();\n        $controllerArgumentsEvent = new ControllerArgumentsEvent($this->getKernel(), static fn (TestEntity $test) => new Response(), [$entity], $request, null);\n        $listener->onKernelControllerArguments($controllerArgumentsEvent);\n\n        $controllerResponse = $controllerArgumentsEvent->getController()($entity);\n        $responseEvent = new ResponseEvent($this->getKernel(), $request, HttpKernelInterface::MAIN_REQUEST, $controllerResponse);\n        $listener->onKernelResponse($responseEvent);\n\n        $response = $responseEvent->getResponse();\n\n        $this->assertSame(200, $response->getStatusCode());\n        $this->assertTrue($response->headers->has('Etag'));\n        $this->assertStringContainsString(hash('sha256', $entity->getId()), $response->headers->get('Etag'));\n    }\n\n    #[DataProvider('provideLastModifiedHeaderAndEtagClosureCases')]\n    public function testLastModifiedHeaderAndEtagHeadersClosures(\\Closure $lastModifiedClosure, \\Closure $etagClosure)\n    {\n        $entity = new TestEntity();\n\n        $request = $this->createRequest(new Cache(lastModified: $lastModifiedClosure, etag: $etagClosure));\n        $request->attributes->set('date', new \\DateTimeImmutable('Fri, 23 Aug 2013 00:00:00 GMT'));\n        $request->attributes->set('id', '12345');\n\n        $listener = new CacheAttributeListener();\n        $controllerArgumentsEvent = new ControllerArgumentsEvent($this->getKernel(), static fn (TestEntity $test) => new Response(), [$entity], $request, null);\n        $listener->onKernelControllerArguments($controllerArgumentsEvent);\n\n        $controllerResponse = $controllerArgumentsEvent->getController()($entity);\n        $responseEvent = new ResponseEvent($this->getKernel(), $request, HttpKernelInterface::MAIN_REQUEST, $controllerResponse);\n        $listener->onKernelResponse($responseEvent);\n\n        $response = $responseEvent->getResponse();\n\n        $this->assertSame(200, $response->getStatusCode());\n        $this->assertTrue($response->headers->has('Last-Modified'));\n        $this->assertSame('Fri, 23 Aug 2013 00:00:00 GMT', $response->headers->get('Last-Modified'));\n        $this->assertTrue($response->headers->has('Etag'));\n        $this->assertStringContainsString(hash('sha256', $entity->getId()), $response->headers->get('Etag'));\n    }\n\n    public static function provideLastModifiedHeaderAndEtagClosureCases(): iterable\n    {\n        yield 'using arguments' => [\n            static fn (array $arguments, Request $request) => $arguments['test']->getDate(),\n            static fn (array $arguments, Request $request) => $arguments['test']->getId(),\n        ];\n\n        yield 'using request attributes' => [\n            static fn (array $arguments, Request $request) => $request->attributes->get('date'),\n            static fn (array $arguments, Request $request) => $request->attributes->get('id'),\n        ];\n    }\n\n    public function testConfigurationDoesNotOverrideAlreadySetResponseHeaders()\n    {\n        $request = $this->createRequest(new Cache(\n            expires: 'Fri, 24 Aug 2013 00:00:00 GMT',\n            maxage: '15',\n            smaxage: '15',\n            vary: ['foobar'],\n            lastModified: 'Fri, 24 Aug 2013 00:00:00 GMT',\n            etag: '\"12345\"',\n        ));\n\n        $response = new Response();\n        $response->setEtag('\"54321\"');\n        $response->setLastModified(new \\DateTimeImmutable('Fri, 23 Aug 2014 00:00:00 GMT'));\n        $response->setExpires(new \\DateTimeImmutable('Fri, 24 Aug 2014 00:00:00 GMT'));\n        $response->setSharedMaxAge(30);\n        $response->setMaxAge(30);\n        $response->setVary(['foobaz']);\n\n        $listener = new CacheAttributeListener();\n        $responseEvent = new ResponseEvent($this->getKernel(), $request, HttpKernelInterface::MAIN_REQUEST, $response);\n        $listener->onKernelResponse($responseEvent);\n\n        $this->assertSame('\"54321\"', $response->getEtag());\n        $this->assertEquals(new \\DateTimeImmutable('Fri, 23 Aug 2014 00:00:00 GMT'), $response->getLastModified());\n        $this->assertEquals(new \\DateTimeImmutable('Fri, 24 Aug 2014 00:00:00 GMT'), $response->getExpires());\n        $this->assertSame('30', $response->headers->getCacheControlDirective('s-maxage'));\n        $this->assertSame(30, $response->getMaxAge());\n        $this->assertSame(['foobaz'], $response->getVary());\n    }\n\n    public function testAttribute()\n    {\n        $request = new Request();\n        $event = new ControllerArgumentsEvent($this->getKernel(), [new CacheAttributeController(), 'foo'], [], $request, null);\n        $this->listener->onKernelControllerArguments($event);\n\n        $response = new Response();\n        $event = new ResponseEvent($this->getKernel(), $request, HttpKernelInterface::MAIN_REQUEST, $response);\n        $this->listener->onKernelResponse($event);\n\n        $this->assertSame(CacheAttributeController::METHOD_SMAXAGE, $response->getMaxAge());\n\n        $request = new Request();\n        $event = new ControllerArgumentsEvent($this->getKernel(), [new CacheAttributeController(), 'bar'], [], $request, null);\n        $this->listener->onKernelControllerArguments($event);\n\n        $response = new Response();\n        $event = new ResponseEvent($this->getKernel(), $request, HttpKernelInterface::MAIN_REQUEST, $response);\n        $this->listener->onKernelResponse($event);\n\n        $this->assertSame(CacheAttributeController::CLASS_SMAXAGE, $response->getMaxAge());\n    }\n\n    #[DataProvider('provideVaryHeaderScenarios')]\n    public function testHasRelevantVaryHeaderBehavior(array $responseVary, array $cacheVary, bool $varyByLanguage, array $expectedVary)\n    {\n        $request = $this->createRequest(new Cache(vary: $cacheVary));\n        $request->attributes->set('_vary_by_language', $varyByLanguage);\n\n        $response = new Response();\n        $response->setVary($responseVary);\n\n        $listener = new CacheAttributeListener();\n        $event = new ResponseEvent($this->getKernel(), $request, HttpKernelInterface::MAIN_REQUEST, $response);\n        $listener->onKernelResponse($event);\n\n        $this->assertSame($expectedVary, $response->getVary());\n    }\n\n    public function testAttributeRespectsExplicitPrivateFromController()\n    {\n        $request = $this->createRequest(new Cache(public: true));\n        $response = new Response();\n        $response->setPrivate();\n\n        $this->listener->onKernelResponse($this->createEventMock($request, $response));\n\n        $this->assertTrue($response->headers->hasCacheControlDirective('private'));\n        $this->assertFalse($response->headers->hasCacheControlDirective('public'));\n    }\n\n    public function testAttributeRespectsExplicitPublicFromController()\n    {\n        $request = $this->createRequest(new Cache(public: false));\n        $response = new Response();\n        $response->setPublic();\n\n        $this->listener->onKernelResponse($this->createEventMock($request, $response));\n\n        $this->assertTrue($response->headers->hasCacheControlDirective('public'));\n        $this->assertFalse($response->headers->hasCacheControlDirective('private'));\n    }\n\n    public static function provideVaryHeaderScenarios(): \\Traversable\n    {\n        yield 'no vary headers at all' => [\n            'responseVary' => [],\n            'cacheVary' => ['X-Foo'],\n            'varyByLanguage' => false,\n            'expectedVary' => ['X-Foo'],\n        ];\n        yield 'response vary accept-language only, vary_by_language true (append new)' => [\n            'responseVary' => ['Accept-Language'],\n            'cacheVary' => ['X-Bar'],\n            'varyByLanguage' => true,\n            'expectedVary' => ['Accept-Language', 'X-Bar'], // X-Bar is added\n        ];\n        yield 'response vary accept-language only, vary_by_language false (no append)' => [\n            'responseVary' => ['Accept-Language'],\n            'cacheVary' => ['X-Bar'],\n            'varyByLanguage' => false,\n            'expectedVary' => ['Accept-Language'], // no append\n        ];\n        yield 'response vary multiple including accept-language, vary_by_language true (no append)' => [\n            'responseVary' => ['Accept-Language', 'User-Agent'],\n            'cacheVary' => ['X-Baz'],\n            'varyByLanguage' => true,\n            'expectedVary' => ['Accept-Language', 'User-Agent'], // no append\n        ];\n        yield 'cache vary is empty' => [\n            'responseVary' => ['X-Existing'],\n            'cacheVary' => [],\n            'varyByLanguage' => true,\n            'expectedVary' => ['X-Existing'], // nothing to add\n        ];\n        yield 'vary * (no append) — vary_by_language=true' => [\n            'responseVary' => ['*'],\n            'cacheVary' => ['X-Foo'],\n            'varyByLanguage' => true,\n            'expectedVary' => ['*'],\n        ];\n        yield 'vary * (no append) — vary_by_language=false' => [\n            'responseVary' => ['*'],\n            'cacheVary' => ['X-Foo'],\n            'varyByLanguage' => false,\n            'expectedVary' => ['*'],\n        ];\n    }\n\n    #[DataProvider('provideCacheIfCases')]\n    public function testCacheAppliedOnlyWhenIfEvaluatesToTrue(string|\\Closure $if1, string|\\Closure $if2, bool $sMaxAge, bool $public, bool $maxAge, bool $private)\n    {\n        $entity = new TestEntity();\n\n        $request = $this->createRequest(\n            new Cache(smaxage: '1 days', public: true, if: $if1),\n            new Cache(maxage: '10 days', public: false, if: $if2),\n        );\n\n        $listener = new CacheAttributeListener();\n        $controllerArgumentsEvent = new ControllerArgumentsEvent($this->getKernel(), [new TestController(true), '__invoke'], [$entity], $request, null);\n        $listener->onKernelControllerArguments($controllerArgumentsEvent);\n\n        $controllerResponse = $controllerArgumentsEvent->getController()($entity);\n        $responseEvent = new ResponseEvent($this->getKernel(), $request, HttpKernelInterface::MAIN_REQUEST, $controllerResponse);\n        $listener->onKernelResponse($responseEvent);\n\n        $response = $responseEvent->getResponse();\n\n        $this->assertSame(200, $response->getStatusCode());\n\n        $this->assertSame($sMaxAge, $response->headers->hasCacheControlDirective('s-maxage'));\n        $this->assertSame($public, $response->headers->hasCacheControlDirective('public'));\n        $this->assertSame($maxAge, $response->headers->hasCacheControlDirective('max-age'));\n        $this->assertSame($private, $response->headers->hasCacheControlDirective('private'));\n    }\n\n    public static function provideCacheIfCases(): iterable\n    {\n        yield 'expression' => [\n            'args[\"test\"].getId() <= 0',\n            'args[\"test\"].getId() > 0',\n            false,\n            false,\n            true,\n            true,\n        ];\n\n        yield 'expression accessing controller' => [\n            'this.cache',\n            'not this.cache',\n            true,\n            true,\n            false,\n            false,\n        ];\n\n        yield 'closure' => [\n            static fn (array $arguments, Request $request, ?object $controller) => $arguments['test']->getDate() <= new \\DateTimeImmutable(),\n            static fn (array $arguments, Request $request, ?object $controller) => $arguments['test']->getDate() > new \\DateTimeImmutable(),\n            true,\n            true,\n            false,\n            false,\n        ];\n\n        yield 'closure accessing controller' => [\n            static fn (array $arguments, Request $request, ?object $controller) => $controller->cache,\n            static fn (array $arguments, Request $request, ?object $controller) => !$controller->cache,\n            true,\n            true,\n            false,\n            false,\n        ];\n    }\n\n    public function testErrorIsThrownWhenIfEvaluatesToNonBool()\n    {\n        $entity = new TestEntity();\n\n        $request = $this->createRequest(\n            new Cache(smaxage: '1 days', public: true, if: static fn (array $arguments, Request $request) => 'foo'),\n        );\n\n        $listener = new CacheAttributeListener();\n        $controllerArgumentsEvent = new ControllerArgumentsEvent($this->getKernel(), static fn (TestEntity $test) => new Response(), [$entity], $request, null);\n\n        $this->expectException(\\TypeError::class);\n        $this->expectExceptionMessage(\\sprintf('The value of the \"$if\" option of the \"%s\" attribute must evaluate to a boolean, \"string\" given.', Cache::class));\n\n        $listener->onKernelControllerArguments($controllerArgumentsEvent);\n    }\n\n    private function createRequest(Cache ...$cache): Request\n    {\n        return new Request([], [], ['_cache' => $cache]);\n    }\n\n    private function createEventMock(Request $request, Response $response): ResponseEvent\n    {\n        return new ResponseEvent($this->getKernel(), $request, HttpKernelInterface::MAIN_REQUEST, $response);\n    }\n\n    private function getKernel(): Stub&HttpKernelInterface\n    {\n        return $this->createStub(HttpKernelInterface::class);\n    }\n}\n\nclass TestEntity\n{\n    public function getDate()\n    {\n        return new \\DateTimeImmutable('Fri, 23 Aug 2013 00:00:00 GMT');\n    }\n\n    public function getId()\n    {\n        return '12345';\n    }\n}\n\nclass TestController\n{\n    public function __construct(public bool $cache)\n    {\n    }\n\n    public function __invoke(TestEntity $test)\n    {\n        return new Response();\n    }\n}\n"
  },
  {
    "path": "Tests/EventListener/ControllerAttributesListenerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\EventListener;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\EventDispatcher\\EventDispatcher;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsMetadata;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerAttributeEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\EventListener\\ControllerAttributesListener;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute\\Buz;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute\\Qux;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller\\ControllerAttributesController;\n\nclass ControllerAttributesListenerTest extends TestCase\n{\n    public function testOnKernelControllerArgumentsDispatchesEventsForEachAttribute()\n    {\n        $dispatchedEvents = [];\n\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS.'.'.Buz::class, static function ($event, $name) use (&$dispatchedEvents) {\n            $dispatchedEvents[] = $name;\n        });\n        $dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS.'.'.Qux::class, static function ($event, $name) use (&$dispatchedEvents) {\n            $dispatchedEvents[] = $name;\n        });\n\n        $listener = $this->createListener();\n        $event = $this->createControllerArgumentsEvent('buzQuxAction');\n\n        $listener->beforeController($event, KernelEvents::CONTROLLER_ARGUMENTS, $dispatcher);\n\n        $this->assertSame([\n            KernelEvents::CONTROLLER_ARGUMENTS.'.'.Buz::class,\n            KernelEvents::CONTROLLER_ARGUMENTS.'.'.Buz::class,\n            KernelEvents::CONTROLLER_ARGUMENTS.'.'.Qux::class,\n        ], $dispatchedEvents);\n    }\n\n    public function testOnKernelResponseDispatchesEventsInReverseOrder()\n    {\n        $dispatchedEvents = [];\n\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::RESPONSE.'.'.Buz::class, static function ($event, $name) use (&$dispatchedEvents) {\n            $dispatchedEvents[] = $name;\n        });\n        $dispatcher->addListener(KernelEvents::RESPONSE.'.'.Qux::class, static function ($event, $name) use (&$dispatchedEvents) {\n            $dispatchedEvents[] = $name;\n        });\n\n        $listener = $this->createListener();\n        $event = $this->createResponseEvent('buzQuxAction');\n\n        $listener->afterController($event, KernelEvents::RESPONSE, $dispatcher);\n\n        $this->assertSame([\n            KernelEvents::RESPONSE.'.'.Qux::class,\n            KernelEvents::RESPONSE.'.'.Buz::class,\n            KernelEvents::RESPONSE.'.'.Buz::class,\n        ], $dispatchedEvents);\n    }\n\n    public function testOnKernelResponseDoesNothingWhenNoControllerEvent()\n    {\n        $dispatchedEvents = [];\n\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::RESPONSE.'.'.Buz::class, static function ($event, $name) use (&$dispatchedEvents) {\n            $dispatchedEvents[] = $name;\n        });\n\n        $listener = $this->createListener();\n\n        $event = new ResponseEvent(\n            $this->createStub(HttpKernelInterface::class),\n            new Request(),\n            HttpKernelInterface::MAIN_REQUEST,\n            new Response()\n        );\n\n        $listener->afterController($event, KernelEvents::RESPONSE, $dispatcher);\n\n        $this->assertSame([], $dispatchedEvents);\n    }\n\n    public function testDispatchedEventIsTheSameInstance()\n    {\n        $capturedEvents = [];\n\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS.'.'.Buz::class, static function (ControllerAttributeEvent $event) use (&$capturedEvents) {\n            $capturedEvents[] = $event;\n        });\n\n        $listener = $this->createListener();\n        $event = $this->createControllerArgumentsEvent('buzAction');\n\n        $listener->beforeController($event, KernelEvents::CONTROLLER_ARGUMENTS, $dispatcher);\n\n        $this->assertCount(2, $capturedEvents);\n        $this->assertSame($event, $capturedEvents[0]->kernelEvent);\n        $this->assertSame($event, $capturedEvents[1]->kernelEvent);\n    }\n\n    public function testClassLevelAttributesAreIncluded()\n    {\n        $dispatchedEvents = [];\n\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS.'.'.Buz::class, static function ($event, $name) use (&$dispatchedEvents) {\n            $dispatchedEvents[] = $name;\n        });\n\n        $listener = $this->createListener();\n        $event = $this->createControllerArgumentsEvent('noAttributeAction');\n\n        $listener->beforeController($event, KernelEvents::CONTROLLER_ARGUMENTS, $dispatcher);\n\n        $this->assertSame([KernelEvents::CONTROLLER_ARGUMENTS.'.'.Buz::class], $dispatchedEvents);\n    }\n\n    public function testBeforeControllerDispatchesParentAttributeListeners()\n    {\n        $dispatchedEvents = [];\n\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS.'.'.Buz::class, static function ($event, $name) use (&$dispatchedEvents) {\n            $dispatchedEvents[] = $name;\n        });\n\n        $listener = $this->createListener([\n            KernelEvents::CONTROLLER_ARGUMENTS => [\n                Buz::class => true,\n            ],\n        ]);\n        $event = $this->createControllerArgumentsEvent('subBuzAction');\n\n        $listener->beforeController($event, KernelEvents::CONTROLLER_ARGUMENTS, $dispatcher);\n\n        $this->assertSame([\n            KernelEvents::CONTROLLER_ARGUMENTS.'.'.Buz::class,\n            KernelEvents::CONTROLLER_ARGUMENTS.'.'.Buz::class,\n        ], $dispatchedEvents);\n    }\n\n    public function testBeforeControllerSkipsWhenNoAttributeListenersAreRegistered()\n    {\n        $dispatchedEvents = [];\n\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS.'.'.Buz::class, static function () use (&$dispatchedEvents) {\n            $dispatchedEvents[] = true;\n        });\n\n        $listener = $this->createListener([]);\n        $event = $this->createControllerArgumentsEvent('buzAction');\n\n        $listener->beforeController($event, KernelEvents::CONTROLLER_ARGUMENTS, $dispatcher);\n\n        $this->assertEmpty($dispatchedEvents);\n    }\n\n    public function testOnKernelControllerHandlesControllerChanges()\n    {\n        $dispatchedEvents = [];\n\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::CONTROLLER.'.'.Buz::class, static function ($event, $name) use (&$dispatchedEvents) {\n            $dispatchedEvents[] = $name;\n        });\n        $dispatcher->addListener(KernelEvents::CONTROLLER.'.'.Qux::class, static function ($event, $name) use (&$dispatchedEvents) {\n            $dispatchedEvents[] = $name;\n        });\n\n        $originalControllerSet = false;\n        $dispatcher->addListener(KernelEvents::CONTROLLER.'.'.Buz::class, static function (ControllerAttributeEvent $event) use (&$originalControllerSet, &$dispatchedEvents) {\n            if (!$originalControllerSet) {\n                $event->kernelEvent->setController([new ControllerAttributesController(), 'buzQuxAction']);\n                $originalControllerSet = true;\n            }\n        }, -1);\n\n        $listener = $this->createListener();\n\n        $event = new ControllerEvent(\n            $this->createStub(HttpKernelInterface::class),\n            [new ControllerAttributesController(), 'buzAction'],\n            new Request(),\n            HttpKernelInterface::MAIN_REQUEST\n        );\n\n        $listener->beforeController($event, KernelEvents::CONTROLLER, $dispatcher);\n\n        $this->assertContains(KernelEvents::CONTROLLER.'.'.Qux::class, $dispatchedEvents);\n    }\n\n    public function testOnKernelControllerArgumentsHandlesControllerChanges()\n    {\n        $dispatchedEvents = [];\n\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS.'.'.Buz::class, static function ($event, $name) use (&$dispatchedEvents) {\n            $dispatchedEvents[] = $name;\n        });\n        $dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS.'.'.Qux::class, static function ($event, $name) use (&$dispatchedEvents) {\n            $dispatchedEvents[] = $name;\n        });\n\n        $listener = $this->createListener();\n        $event = $this->createControllerArgumentsEvent('buzAction');\n\n        $originalControllerSet = false;\n        $dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS.'.'.Buz::class, static function (ControllerAttributeEvent $event) use (&$originalControllerSet, &$dispatchedEvents) {\n            if (!$originalControllerSet) {\n                $event->kernelEvent->setController([new ControllerAttributesController(), 'buzQuxAction']);\n                $originalControllerSet = true;\n            }\n        }, -1);\n\n        $listener->beforeController($event, KernelEvents::CONTROLLER_ARGUMENTS, $dispatcher);\n\n        $this->assertContains(KernelEvents::CONTROLLER_ARGUMENTS.'.'.Qux::class, $dispatchedEvents);\n    }\n\n    private function createListener(?array $attributesWithListenersByEvent = null): ControllerAttributesListener\n    {\n        return new ControllerAttributesListener($attributesWithListenersByEvent ?? [\n            KernelEvents::CONTROLLER => [\n                Buz::class => true,\n                Qux::class => true,\n            ],\n            KernelEvents::CONTROLLER_ARGUMENTS => [\n                Buz::class => true,\n                Qux::class => true,\n            ],\n            KernelEvents::VIEW => [\n                Buz::class => true,\n                Qux::class => true,\n            ],\n            KernelEvents::RESPONSE => [\n                Buz::class => true,\n                Qux::class => true,\n            ],\n            KernelEvents::FINISH_REQUEST => [\n                Buz::class => true,\n                Qux::class => true,\n            ],\n        ]);\n    }\n\n    private function createControllerArgumentsEvent(string $method): ControllerArgumentsEvent\n    {\n        return new ControllerArgumentsEvent(\n            $this->createStub(HttpKernelInterface::class),\n            [new ControllerAttributesController(), $method],\n            [],\n            new Request(),\n            HttpKernelInterface::MAIN_REQUEST\n        );\n    }\n\n    private function createResponseEvent(string $method): ResponseEvent\n    {\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $request = new Request();\n        $controller = [new ControllerAttributesController(), $method];\n        $controllerEvent = new ControllerEvent($kernel, $controller, $request, HttpKernelInterface::MAIN_REQUEST);\n        $controllerArgumentsEvent = new ControllerArgumentsEvent($kernel, $controllerEvent, [], $request, HttpKernelInterface::MAIN_REQUEST);\n        $controllerMetadata = new ControllerArgumentsMetadata($controllerEvent, $controllerArgumentsEvent);\n\n        return new ResponseEvent(\n            $kernel,\n            $request,\n            HttpKernelInterface::MAIN_REQUEST,\n            new Response(),\n            $controllerMetadata\n        );\n    }\n}\n"
  },
  {
    "path": "Tests/EventListener/DebugHandlersListenerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\EventListener;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Console\\Application;\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\ConsoleEvents;\nuse Symfony\\Component\\Console\\Event\\ConsoleEvent;\nuse Symfony\\Component\\Console\\Helper\\HelperSet;\nuse Symfony\\Component\\Console\\Input\\ArgvInput;\nuse Symfony\\Component\\Console\\Output\\ConsoleOutput;\nuse Symfony\\Component\\ErrorHandler\\ErrorHandler;\nuse Symfony\\Component\\EventDispatcher\\EventDispatcher;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Event\\KernelEvent;\nuse Symfony\\Component\\HttpKernel\\EventListener\\DebugHandlersListener;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass DebugHandlersListenerTest extends TestCase\n{\n    public function testConfigure()\n    {\n        $userHandler = static fn () => null;\n        $listener = new DebugHandlersListener($userHandler);\n        $eHandler = new ErrorHandler();\n\n        $exception = null;\n        set_error_handler([$eHandler, 'handleError']);\n        set_exception_handler([$eHandler, 'handleException']);\n        try {\n            $listener->configure();\n        } catch (\\Exception $exception) {\n        } finally {\n            restore_exception_handler();\n            restore_error_handler();\n        }\n\n        if (null !== $exception) {\n            throw $exception;\n        }\n\n        $this->assertSame($userHandler, $eHandler->setExceptionHandler('var_dump'));\n    }\n\n    public function testConfigureForHttpKernelWithNoTerminateWithException()\n    {\n        $listener = new DebugHandlersListener(null);\n        $eHandler = new ErrorHandler();\n        $event = new KernelEvent(\n            $this->createStub(HttpKernelInterface::class),\n            Request::create('/'),\n            HttpKernelInterface::MAIN_REQUEST\n        );\n\n        $exception = null;\n        $h = set_exception_handler([$eHandler, 'handleException']);\n        try {\n            $listener->configure($event);\n        } catch (\\Exception $exception) {\n        }\n        restore_exception_handler();\n\n        if (null !== $exception) {\n            throw $exception;\n        }\n\n        $this->assertNull($h);\n    }\n\n    public function testConsoleEvent()\n    {\n        $dispatcher = new EventDispatcher();\n        $listener = new DebugHandlersListener(null);\n        $app = $this->createMock(Application::class);\n        $app->expects($this->once())->method('getHelperSet')->willReturn(new HelperSet());\n        $command = new Command(__FUNCTION__);\n        $command->setApplication($app);\n        $event = new ConsoleEvent($command, new ArgvInput(), new ConsoleOutput());\n\n        $dispatcher->addSubscriber($listener);\n\n        $xListeners = [\n            KernelEvents::REQUEST => [[$listener, 'configure']],\n            ConsoleEvents::COMMAND => [[$listener, 'configure']],\n        ];\n        $this->assertSame($xListeners, $dispatcher->getListeners());\n\n        $exception = null;\n        $eHandler = new ErrorHandler();\n        set_error_handler([$eHandler, 'handleError']);\n        set_exception_handler([$eHandler, 'handleException']);\n        try {\n            $dispatcher->dispatch($event, ConsoleEvents::COMMAND);\n        } catch (\\Exception $exception) {\n        } finally {\n            restore_exception_handler();\n            restore_error_handler();\n        }\n\n        if (null !== $exception) {\n            throw $exception;\n        }\n\n        $xHandler = $eHandler->setExceptionHandler('var_dump');\n        $this->assertInstanceOf(\\Closure::class, $xHandler);\n\n        $app->expects($this->once())\n            ->method('renderThrowable');\n\n        $xHandler(new \\Exception());\n    }\n\n    public function testReplaceExistingExceptionHandler()\n    {\n        $userHandler = static function () {};\n        $listener = new DebugHandlersListener($userHandler);\n        $eHandler = new ErrorHandler();\n        $eHandler->setExceptionHandler('var_dump');\n\n        $exception = null;\n        set_exception_handler([$eHandler, 'handleException']);\n        try {\n            $listener->configure();\n        } catch (\\Exception $exception) {\n        }\n        restore_exception_handler();\n\n        if (null !== $exception) {\n            throw $exception;\n        }\n\n        $this->assertSame($userHandler, $eHandler->setExceptionHandler('var_dump'));\n    }\n}\n"
  },
  {
    "path": "Tests/EventListener/DisallowRobotsIndexingListenerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\EventListener;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\EventListener\\DisallowRobotsIndexingListener;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\KernelInterface;\n\nclass DisallowRobotsIndexingListenerTest extends TestCase\n{\n    #[DataProvider('provideResponses')]\n    public function testInvoke(?string $expected, array $responseArgs)\n    {\n        $response = new Response(...$responseArgs);\n        $listener = new DisallowRobotsIndexingListener();\n\n        $event = new ResponseEvent($this->createStub(HttpKernelInterface::class), new Request(), KernelInterface::MAIN_REQUEST, $response);\n\n        $listener->onResponse($event);\n\n        $this->assertSame($expected, $response->headers->get('X-Robots-Tag'), 'Header doesn\\'t match expectations');\n    }\n\n    public static function provideResponses(): iterable\n    {\n        yield 'No header' => ['noindex', []];\n\n        yield 'Header already set' => [\n            'something else',\n            ['', 204, ['X-Robots-Tag' => 'something else']],\n        ];\n    }\n}\n"
  },
  {
    "path": "Tests/EventListener/DumpListenerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\EventListener;\n\nuse PHPUnit\\Framework\\Attributes\\TestWith;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Console\\ConsoleEvents;\nuse Symfony\\Component\\Console\\Event\\ConsoleCommandEvent;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Output\\BufferedOutput;\nuse Symfony\\Component\\HttpKernel\\EventListener\\DumpListener;\nuse Symfony\\Component\\VarDumper\\Cloner\\ClonerInterface;\nuse Symfony\\Component\\VarDumper\\Cloner\\Data;\nuse Symfony\\Component\\VarDumper\\Dumper\\DataDumperInterface;\nuse Symfony\\Component\\VarDumper\\VarDumper;\n\n/**\n * DumpListenerTest.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass DumpListenerTest extends TestCase\n{\n    public function testSubscribedEvents()\n    {\n        $this->assertSame(\n            [ConsoleEvents::COMMAND => ['configure', 1024]],\n            DumpListener::getSubscribedEvents()\n        );\n    }\n\n    public function testConfigure()\n    {\n        $prevDumper = VarDumper::setHandler('var_dump');\n        VarDumper::setHandler($prevDumper);\n\n        $cloner = new MockCloner();\n        $dumper = new MockDumper();\n\n        ob_start();\n        $exception = null;\n        $listener = new DumpListener($cloner, $dumper);\n\n        try {\n            $listener->configure();\n\n            VarDumper::dump('foo');\n            VarDumper::dump('bar');\n\n            $this->assertSame('+foo-+bar-', ob_get_clean());\n        } catch (\\Exception $exception) {\n        }\n\n        VarDumper::setHandler($prevDumper);\n\n        if (null !== $exception) {\n            throw $exception;\n        }\n    }\n\n    #[TestWith([false, false, '+foo-+bar-', []])]\n    #[TestWith([true, false, '+foo-+bar-', []])]\n    #[TestWith([true, true, '', ['foo-', 'bar-']])]\n    public function testConfigureWithProfilerDumper(bool $hasOption, bool $option, string $expectedOutput, array $expectedData)\n    {\n        $prevDumper = VarDumper::setHandler('var_dump');\n        VarDumper::setHandler($prevDumper);\n\n        $cloner = new MockCloner();\n        $dumper = new MockDumper();\n        $profilerDumper = new MockProfilerDumper();\n\n        $input = $this->createStub(InputInterface::class);\n        $input->method('hasOption')->willReturn($hasOption);\n        $input->method('getOption')->willReturn($option);\n\n        ob_start();\n        $exception = null;\n        $listener = new DumpListener($cloner, $dumper, null, $profilerDumper);\n\n        try {\n            $listener->configure(new ConsoleCommandEvent(null, $input, new BufferedOutput()));\n\n            VarDumper::dump('foo');\n            VarDumper::dump('bar');\n\n            $this->assertSame($expectedOutput, ob_get_clean());\n            $this->assertSame($expectedData, $profilerDumper->data);\n        } catch (\\Exception $exception) {\n        }\n\n        VarDumper::setHandler($prevDumper);\n\n        if (null !== $exception) {\n            throw $exception;\n        }\n    }\n}\n\nclass MockCloner implements ClonerInterface\n{\n    public function cloneVar($var): Data\n    {\n        return new Data([[$var.'-']]);\n    }\n}\n\nclass MockDumper implements DataDumperInterface\n{\n    public function dump(Data $data): ?string\n    {\n        echo '+'.$data->getValue();\n\n        return null;\n    }\n}\n\nclass MockProfilerDumper implements DataDumperInterface\n{\n    public array $data = [];\n\n    public function dump(Data $data): ?string\n    {\n        $this->data[] = $data->getValue();\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "Tests/EventListener/ErrorListenerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\EventListener;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\Attributes\\Group;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LogLevel;\nuse Psr\\Log\\NullLogger;\nuse Symfony\\Component\\ErrorHandler\\Exception\\FlattenException;\nuse Symfony\\Component\\EventDispatcher\\EventDispatcher;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Attribute\\WithHttpStatus;\nuse Symfony\\Component\\HttpKernel\\Attribute\\WithLogLevel;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ExceptionEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\EventListener\\ErrorListener;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpExceptionInterface;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\nuse Symfony\\Component\\HttpKernel\\Log\\DebugLoggerInterface;\nuse Symfony\\Component\\HttpKernel\\Tests\\Logger;\n\n/**\n * @author Robert Schönthal <seroscho@googlemail.com>\n */\n#[Group('time-sensitive')]\nclass ErrorListenerTest extends TestCase\n{\n    public function testConstruct()\n    {\n        $logger = new TestLogger();\n        $l = new ErrorListener('foo', $logger);\n\n        $_logger = new \\ReflectionProperty($l::class, 'logger');\n        $_controller = new \\ReflectionProperty($l::class, 'controller');\n\n        $this->assertSame($logger, $_logger->getValue($l));\n        $this->assertSame('foo', $_controller->getValue($l));\n    }\n\n    #[DataProvider('provider')]\n    public function testHandleWithoutLogger($event, $event2)\n    {\n        $initialErrorLog = ini_set('error_log', file_exists('/dev/null') ? '/dev/null' : 'nul');\n\n        try {\n            $l = new ErrorListener('foo');\n            $l->logKernelException($event);\n            $l->onKernelException($event);\n\n            $this->assertEquals(new Response('foo'), $event->getResponse());\n\n            try {\n                $l->logKernelException($event2);\n                $l->onKernelException($event2);\n                $this->fail('RuntimeException expected');\n            } catch (\\RuntimeException $e) {\n                $this->assertSame('bar', $e->getMessage());\n                $this->assertSame('foo', $e->getPrevious()->getMessage());\n            }\n        } finally {\n            ini_set('error_log', $initialErrorLog);\n        }\n    }\n\n    #[DataProvider('provider')]\n    public function testHandleWithLogger($event, $event2)\n    {\n        $logger = new TestLogger();\n\n        $l = new ErrorListener('foo', $logger);\n        $l->logKernelException($event);\n        $l->onKernelException($event);\n\n        $this->assertEquals(new Response('foo'), $event->getResponse());\n\n        try {\n            $l->logKernelException($event2);\n            $l->onKernelException($event2);\n            $this->fail('RuntimeException expected');\n        } catch (\\RuntimeException $e) {\n            $this->assertSame('bar', $e->getMessage());\n            $this->assertSame('foo', $e->getPrevious()->getMessage());\n        }\n\n        $this->assertEquals(3, $logger->countErrors());\n        $logs = $logger->getLogsForLevel('critical');\n        $this->assertCount(3, $logs);\n        $this->assertStringStartsWith('Uncaught PHP Exception Exception: \"foo\" at ErrorListenerTest.php line', $logs[0]);\n        $this->assertStringStartsWith('Uncaught PHP Exception Exception: \"foo\" at ErrorListenerTest.php line', $logs[1]);\n        $this->assertStringStartsWith('Exception thrown when handling an exception (RuntimeException: bar at ErrorListenerTest.php line', $logs[2]);\n    }\n\n    public function testHandleWithLoggerAndCustomConfiguration()\n    {\n        $request = new Request();\n        $event = new ExceptionEvent(new TestKernel(), $request, HttpKernelInterface::MAIN_REQUEST, new \\RuntimeException('bar'));\n        $logger = new TestLogger();\n        $l = new ErrorListener('not used', $logger, false, [\n            \\RuntimeException::class => [\n                'log_level' => 'warning',\n                'status_code' => 401,\n            ],\n        ]);\n        $l->logKernelException($event);\n        $l->onKernelException($event);\n\n        $this->assertEquals(new Response('foo', 401), $event->getResponse());\n\n        $this->assertEquals(0, $logger->countErrors());\n        $this->assertCount(0, $logger->getLogsForLevel('critical'));\n        $this->assertCount(1, $logger->getLogsForLevel('warning'));\n    }\n\n    public function testHandleWithLogLevelAttribute()\n    {\n        $request = new Request();\n        $event = new ExceptionEvent(new TestKernel(), $request, HttpKernelInterface::MAIN_REQUEST, new ChildOfWarningWithLogLevelAttribute());\n        $logger = new TestLogger();\n        $l = new ErrorListener('not used', $logger);\n\n        $l->logKernelException($event);\n        $l->onKernelException($event);\n\n        $this->assertEquals(0, $logger->countErrors());\n        $this->assertCount(0, $logger->getLogsForLevel('critical'));\n        $this->assertCount(1, $logger->getLogsForLevel('warning'));\n    }\n\n    public function testHandleWithLogChannel()\n    {\n        $request = new Request();\n        $event = new ExceptionEvent(new TestKernel(), $request, HttpKernelInterface::MAIN_REQUEST, new \\RuntimeException('bar'));\n\n        $defaultLogger = new TestLogger();\n        $channelLoger = new TestLogger();\n\n        $l = new ErrorListener('not used', $defaultLogger, false, [\n            \\RuntimeException::class => [\n                'log_level' => 'warning',\n                'status_code' => 401,\n                'log_channel' => 'channel',\n            ],\n            \\Exception::class => [\n                'log_level' => 'error',\n                'status_code' => 402,\n            ],\n        ], ['channel' => $channelLoger]);\n\n        $l->logKernelException($event);\n        $l->onKernelException($event);\n\n        $this->assertCount(0, $defaultLogger->getLogsForLevel('error'));\n        $this->assertCount(0, $defaultLogger->getLogsForLevel('warning'));\n        $this->assertCount(0, $channelLoger->getLogsForLevel('error'));\n        $this->assertCount(1, $channelLoger->getLogsForLevel('warning'));\n    }\n\n    public function testHandleWithLoggerChannelNotUsed()\n    {\n        $request = new Request();\n        $event = new ExceptionEvent(new TestKernel(), $request, HttpKernelInterface::MAIN_REQUEST, new \\RuntimeException('bar'));\n        $defaultLogger = new TestLogger();\n        $channelLoger = new TestLogger();\n        $l = new ErrorListener('not used', $defaultLogger, false, [\n            \\RuntimeException::class => [\n                'log_level' => 'warning',\n                'status_code' => 401,\n            ],\n            \\ErrorException::class => [\n                'log_level' => 'error',\n                'status_code' => 402,\n                'log_channel' => 'channel',\n            ],\n        ], ['channel' => $channelLoger]);\n        $l->logKernelException($event);\n        $l->onKernelException($event);\n\n        $this->assertSame(0, $defaultLogger->countErrors());\n        $this->assertCount(0, $defaultLogger->getLogsForLevel('critical'));\n        $this->assertCount(1, $defaultLogger->getLogsForLevel('warning'));\n        $this->assertCount(0, $channelLoger->getLogsForLevel('warning'));\n        $this->assertCount(0, $channelLoger->getLogsForLevel('error'));\n        $this->assertCount(0, $channelLoger->getLogsForLevel('critical'));\n    }\n\n    public function testHandleClassImplementingInterfaceWithLogLevelAttribute()\n    {\n        $request = new Request();\n        $event = new ExceptionEvent(new TestKernel(), $request, HttpKernelInterface::MAIN_REQUEST, new ImplementingInterfaceWithLogLevelAttribute());\n        $logger = new TestLogger();\n        $l = new ErrorListener('not used', $logger);\n\n        $l->logKernelException($event);\n        $l->onKernelException($event);\n\n        $this->assertEquals(0, $logger->countErrors());\n        $this->assertCount(0, $logger->getLogsForLevel('critical'));\n        $this->assertCount(1, $logger->getLogsForLevel('warning'));\n    }\n\n    public function testHandleWithLogLevelAttributeAndCustomConfiguration()\n    {\n        $request = new Request();\n        $event = new ExceptionEvent(new TestKernel(), $request, HttpKernelInterface::MAIN_REQUEST, new WarningWithLogLevelAttribute());\n        $logger = new TestLogger();\n        $l = new ErrorListener('not used', $logger, false, [\n            WarningWithLogLevelAttribute::class => [\n                'log_level' => 'info',\n                'status_code' => 401,\n            ],\n        ]);\n        $l->logKernelException($event);\n        $l->onKernelException($event);\n\n        $this->assertEquals(0, $logger->countErrors());\n        $this->assertCount(0, $logger->getLogsForLevel('warning'));\n        $this->assertCount(1, $logger->getLogsForLevel('info'));\n    }\n\n    #[DataProvider('exceptionWithAttributeProvider')]\n    public function testHandleHttpAttribute(\\Throwable $exception, int $expectedStatusCode, array $expectedHeaders)\n    {\n        $request = new Request();\n        $event = new ExceptionEvent(new TestKernel(), $request, HttpKernelInterface::MAIN_REQUEST, $exception);\n        $l = new ErrorListener('not used');\n        $l->logKernelException($event);\n        $l->onKernelException($event);\n\n        $this->assertEquals(new Response('foo', $expectedStatusCode, $expectedHeaders), $event->getResponse());\n    }\n\n    public function testHandleCustomConfigurationAndHttpAttribute()\n    {\n        $request = new Request();\n        $event = new ExceptionEvent(new TestKernel(), $request, HttpKernelInterface::MAIN_REQUEST, new WithGeneralAttribute());\n        $l = new ErrorListener('not used', null, false, [\n            WithGeneralAttribute::class => [\n                'log_level' => 'warning',\n                'status_code' => 401,\n            ],\n        ]);\n        $l->logKernelException($event);\n        $l->onKernelException($event);\n\n        $this->assertEquals(new Response('foo', 401), $event->getResponse());\n    }\n\n    public static function provider()\n    {\n        if (!class_exists(Request::class)) {\n            return [[null, null]];\n        }\n\n        $request = new Request();\n        $exception = new \\Exception('foo');\n        $event = new ExceptionEvent(new TestKernel(), $request, HttpKernelInterface::MAIN_REQUEST, $exception);\n        $event2 = new ExceptionEvent(new TestKernelThatThrowsException(), $request, HttpKernelInterface::MAIN_REQUEST, $exception);\n\n        return [\n            [$event, $event2],\n        ];\n    }\n\n    public function testSubRequestFormat()\n    {\n        $listener = new ErrorListener('foo', new NullLogger());\n\n        $kernel = $this->createMock(HttpKernelInterface::class);\n        $kernel->expects($this->once())->method('handle')->willReturnCallback(static fn (Request $request) => new Response($request->getRequestFormat()));\n\n        $request = Request::create('/');\n        $request->setRequestFormat('xml');\n\n        $event = new ExceptionEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, new \\Exception('foo'));\n        $listener->onKernelException($event);\n\n        $response = $event->getResponse();\n        $this->assertEquals('xml', $response->getContent());\n    }\n\n    public function testCSPHeaderIsRemoved()\n    {\n        $dispatcher = new EventDispatcher();\n        $kernel = $this->createMock(HttpKernelInterface::class);\n        $kernel->expects($this->once())->method('handle')->willReturnCallback(static fn (Request $request) => new Response($request->getRequestFormat()));\n\n        $listener = new ErrorListener('foo', new NullLogger(), true);\n\n        $dispatcher->addSubscriber($listener);\n\n        $request = Request::create('/');\n        $event = new ExceptionEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, new \\Exception('foo'));\n        $dispatcher->dispatch($event, KernelEvents::EXCEPTION);\n\n        $response = new Response('', 200, ['content-security-policy' => \"style-src 'self'\"]);\n        $this->assertTrue($response->headers->has('content-security-policy'));\n\n        $event = new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response);\n        $dispatcher->dispatch($event, KernelEvents::RESPONSE);\n\n        $this->assertFalse($response->headers->has('content-security-policy'), 'CSP header has been removed');\n    }\n\n    public function testTerminating()\n    {\n        $listener = new ErrorListener('foo', new NullLogger());\n\n        $kernel = $this->createMock(HttpKernelInterface::class);\n        $kernel->expects($this->never())->method('handle');\n\n        $request = Request::create('/');\n\n        $event = new ExceptionEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, new \\Exception('foo'), true);\n        $listener->onKernelException($event);\n    }\n\n    #[DataProvider('controllerProvider')]\n    public function testOnControllerArguments(callable $controller)\n    {\n        $listener = new ErrorListener($controller, new NullLogger(), true);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $kernel->method('handle')->willReturnCallback(function (Request $request) use ($listener, $controller, $kernel) {\n            $this->assertSame($controller, $request->attributes->get('_controller'));\n            $arguments = (new ArgumentResolver())->getArguments($request, $controller);\n            $event = new ControllerArgumentsEvent($kernel, $controller, $arguments, $request, HttpKernelInterface::SUB_REQUEST);\n            $listener->onControllerArguments($event);\n\n            return $controller(...$event->getArguments());\n        });\n\n        $event = new ExceptionEvent($kernel, Request::create('/'), HttpKernelInterface::MAIN_REQUEST, new \\Exception('foo'));\n        $listener->onKernelException($event);\n\n        $this->assertSame('OK: foo', $event->getResponse()->getContent());\n    }\n\n    public static function controllerProvider()\n    {\n        yield [static fn (FlattenException $exception) => new Response('OK: '.$exception->getMessage())];\n\n        yield [static function ($exception) {\n            static::assertInstanceOf(FlattenException::class, $exception);\n\n            return new Response('OK: '.$exception->getMessage());\n        }];\n\n        yield [static fn (\\Throwable $exception) => new Response('OK: '.$exception->getMessage())];\n    }\n\n    public static function exceptionWithAttributeProvider()\n    {\n        yield [new WithCustomUserProvidedAttribute(), 208, ['name' => 'value']];\n        yield [new WithGeneralAttribute(), 412, ['some' => 'thing']];\n        yield [new ChildOfWithGeneralAttribute(), 412, ['some' => 'thing']];\n        yield [new ImplementingInterfaceWithGeneralAttribute(), 412, ['some' => 'thing']];\n    }\n}\n\nclass TestLogger extends Logger implements DebugLoggerInterface\n{\n    public function countErrors(?Request $request = null): int\n    {\n        return \\count($this->logs['critical']);\n    }\n\n    public function getLogs(?Request $request = null): array\n    {\n        return [];\n    }\n}\n\nclass TestKernel implements HttpKernelInterface\n{\n    public function handle(Request $request, $type = self::MAIN_REQUEST, $catch = true): Response\n    {\n        $e = $request->attributes->get('exception');\n        if ($e instanceof HttpExceptionInterface) {\n            return new Response('foo', $e->getStatusCode(), $e->getHeaders());\n        }\n\n        return new Response('foo');\n    }\n}\n\nclass TestKernelThatThrowsException implements HttpKernelInterface\n{\n    public function handle(Request $request, $type = self::MAIN_REQUEST, $catch = true): Response\n    {\n        throw new \\RuntimeException('bar');\n    }\n}\n\n#[\\Attribute(\\Attribute::TARGET_CLASS)]\nclass UserProvidedHttpStatusCodeAttribute extends WithHttpStatus\n{\n    public function __construct(array $headers = [])\n    {\n        parent::__construct(\n            Response::HTTP_ALREADY_REPORTED,\n            $headers\n        );\n    }\n}\n\n#[UserProvidedHttpStatusCodeAttribute(headers: [\n    'name' => 'value',\n])]\nclass WithCustomUserProvidedAttribute extends \\Exception\n{\n}\n\n#[WithHttpStatus(\n    statusCode: Response::HTTP_PRECONDITION_FAILED,\n    headers: [\n        'some' => 'thing',\n    ]\n)]\nclass WithGeneralAttribute extends \\Exception\n{\n}\n\n#[WithHttpStatus(\n    statusCode: Response::HTTP_PRECONDITION_FAILED,\n    headers: [\n        'some' => 'thing',\n    ]\n)]\ninterface InterfaceWithGeneralAttribute\n{\n}\n\nclass ImplementingInterfaceWithGeneralAttribute extends \\Exception implements InterfaceWithGeneralAttribute\n{\n}\n\nclass ChildOfWithGeneralAttribute extends WithGeneralAttribute\n{\n}\n\n#[WithLogLevel(LogLevel::WARNING)]\nclass WarningWithLogLevelAttribute extends \\Exception\n{\n}\n\nclass ChildOfWarningWithLogLevelAttribute extends WarningWithLogLevelAttribute\n{\n}\n\n#[WithLogLevel(LogLevel::WARNING)]\ninterface InterfaceWithLogLevelAttribute\n{\n}\n\nclass ImplementingInterfaceWithLogLevelAttribute extends \\Exception implements InterfaceWithLogLevelAttribute\n{\n}\n"
  },
  {
    "path": "Tests/EventListener/FragmentListenerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\EventListener;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\UriSigner;\nuse Symfony\\Component\\HttpKernel\\Event\\RequestEvent;\nuse Symfony\\Component\\HttpKernel\\EventListener\\FragmentListener;\nuse Symfony\\Component\\HttpKernel\\Exception\\AccessDeniedHttpException;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\n\nclass FragmentListenerTest extends TestCase\n{\n    public function testOnlyTriggeredOnFragmentRoute()\n    {\n        $request = Request::create('http://example.com/foo?_path=foo%3Dbar%26_controller%3Dfoo');\n\n        $listener = new FragmentListener(new UriSigner('foo'));\n        $event = $this->createRequestEvent($request);\n\n        $expected = $request->attributes->all();\n\n        $listener->onKernelRequest($event);\n\n        $this->assertEquals($expected, $request->attributes->all());\n        $this->assertTrue($request->query->has('_path'));\n    }\n\n    public function testOnlyTriggeredIfControllerWasNotDefinedYet()\n    {\n        $request = Request::create('http://example.com/_fragment?_path=foo%3Dbar%26_controller%3Dfoo');\n        $request->attributes->set('_controller', 'bar');\n\n        $listener = new FragmentListener(new UriSigner('foo'));\n        $event = $this->createRequestEvent($request, HttpKernelInterface::SUB_REQUEST);\n\n        $expected = $request->attributes->all();\n\n        $listener->onKernelRequest($event);\n\n        $this->assertEquals($expected, $request->attributes->all());\n    }\n\n    public function testAccessDeniedWithNonSafeMethods()\n    {\n        $this->expectException(AccessDeniedHttpException::class);\n        $request = Request::create('http://example.com/_fragment', 'POST');\n\n        $listener = new FragmentListener(new UriSigner('foo'));\n        $event = $this->createRequestEvent($request);\n\n        $listener->onKernelRequest($event);\n    }\n\n    public function testAccessDeniedWithWrongSignature()\n    {\n        $this->expectException(AccessDeniedHttpException::class);\n        $request = Request::create('http://example.com/_fragment', 'GET', [], [], [], ['REMOTE_ADDR' => '10.0.0.1']);\n\n        $listener = new FragmentListener(new UriSigner('foo'));\n        $event = $this->createRequestEvent($request);\n\n        $listener->onKernelRequest($event);\n    }\n\n    public function testWithSignature()\n    {\n        $signer = new UriSigner('foo');\n        $request = Request::create($signer->sign('http://example.com/_fragment?_path=foo%3Dbar%26_controller%3Dfoo'), 'GET', [], [], [], ['REMOTE_ADDR' => '10.0.0.1']);\n\n        $listener = new FragmentListener($signer);\n        $event = $this->createRequestEvent($request);\n\n        $listener->onKernelRequest($event);\n\n        $this->assertEquals(['foo' => 'bar', '_controller' => 'foo', '_check_controller_is_allowed' => -1], $request->attributes->get('_route_params'));\n        $this->assertFalse($request->query->has('_path'));\n    }\n\n    public function testRemovesPathWithControllerDefined()\n    {\n        $request = Request::create('http://example.com/_fragment?_path=foo%3Dbar%26_controller%3Dfoo');\n\n        $listener = new FragmentListener(new UriSigner('foo'));\n        $event = $this->createRequestEvent($request, HttpKernelInterface::SUB_REQUEST);\n\n        $listener->onKernelRequest($event);\n\n        $this->assertFalse($request->query->has('_path'));\n    }\n\n    public function testRemovesPathWithControllerNotDefined()\n    {\n        $signer = new UriSigner('foo');\n        $request = Request::create($signer->sign('http://example.com/_fragment?_path=foo%3Dbar'), 'GET', [], [], [], ['REMOTE_ADDR' => '10.0.0.1']);\n\n        $listener = new FragmentListener($signer);\n        $event = $this->createRequestEvent($request);\n\n        $listener->onKernelRequest($event);\n\n        $this->assertFalse($request->query->has('_path'));\n    }\n\n    private function createRequestEvent(Request $request, int $requestType = HttpKernelInterface::MAIN_REQUEST): RequestEvent\n    {\n        return new RequestEvent($this->createStub(HttpKernelInterface::class), $request, $requestType);\n    }\n}\n"
  },
  {
    "path": "Tests/EventListener/IsSignatureValidAttributeListenerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\EventListener;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Exception\\UnsignedUriException;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\UriSigner;\nuse Symfony\\Component\\HttpKernel\\Attribute\\IsSignatureValid;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerAttributeEvent;\nuse Symfony\\Component\\HttpKernel\\EventListener\\IsSignatureValidAttributeListener;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\IsSignatureValidAttributeController;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\IsSignatureValidAttributeMethodsController;\n\nclass IsSignatureValidAttributeListenerTest extends TestCase\n{\n    public function testSubscribedEvents()\n    {\n        $events = IsSignatureValidAttributeListener::getSubscribedEvents();\n\n        $eventName = KernelEvents::CONTROLLER_ARGUMENTS.'.'.IsSignatureValid::class;\n\n        $this->assertArrayHasKey($eventName, $events);\n        $this->assertSame('onKernelControllerAttribute', $events[$eventName]);\n    }\n\n    public function testControllerAttributeEventValidatesSignature()\n    {\n        $request = new Request();\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $controllerEvent = new ControllerArgumentsEvent(\n            $kernel,\n            [new IsSignatureValidAttributeController(), '__invoke'],\n            [],\n            $request,\n            HttpKernelInterface::MAIN_REQUEST\n        );\n\n        $signer = $this->createMock(UriSigner::class);\n        $signer->expects($this->once())->method('verify')->with($request);\n\n        $listener = new IsSignatureValidAttributeListener($signer);\n        $listener->onKernelControllerAttribute(new ControllerAttributeEvent(new IsSignatureValid(), $controllerEvent));\n    }\n\n    public function testInvokableControllerWithValidSignature()\n    {\n        $request = new Request();\n\n        $signer = $this->createMock(UriSigner::class);\n        $signer->expects($this->once())->method('verify')->with($request);\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $event = new ControllerArgumentsEvent(\n            $kernel,\n            new IsSignatureValidAttributeController(),\n            [],\n            $request,\n            null\n        );\n\n        $listener = new IsSignatureValidAttributeListener($signer);\n        $listener->onKernelControllerArguments($event);\n    }\n\n    public function testNoAttributeSkipsValidation()\n    {\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $signer = $this->createMock(UriSigner::class);\n        $signer->expects($this->never())->method('verify');\n\n        $event = new ControllerArgumentsEvent(\n            $kernel,\n            [new IsSignatureValidAttributeMethodsController(), 'noAttribute'],\n            [],\n            new Request(),\n            null\n        );\n\n        $listener = new IsSignatureValidAttributeListener($signer);\n        $listener->onKernelControllerArguments($event);\n    }\n\n    public function testDefaultCheckRequestSucceeds()\n    {\n        $request = new Request();\n        $signer = $this->createMock(UriSigner::class);\n        $signer->expects($this->once())->method('verify')->with($request);\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $event = new ControllerArgumentsEvent(\n            $kernel,\n            [new IsSignatureValidAttributeMethodsController(), 'withDefaultBehavior'],\n            [],\n            $request,\n            null\n        );\n\n        $listener = new IsSignatureValidAttributeListener($signer);\n        $listener->onKernelControllerArguments($event);\n    }\n\n    public function testCheckRequestFailsThrowsHttpException()\n    {\n        $request = new Request();\n        $signer = $this->createMock(UriSigner::class);\n        $signer->expects($this->once())->method('verify')->willThrowException(new UnsignedUriException());\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $event = new ControllerArgumentsEvent(\n            $kernel,\n            [new IsSignatureValidAttributeMethodsController(), 'withDefaultBehavior'],\n            [],\n            $request,\n            null\n        );\n\n        $listener = new IsSignatureValidAttributeListener($signer);\n\n        $this->expectException(UnsignedUriException::class);\n        $listener->onKernelControllerArguments($event);\n    }\n\n    public function testMultipleAttributesAllValid()\n    {\n        $request = new Request();\n\n        $signer = $this->createMock(UriSigner::class);\n        $signer->expects($this->exactly(2))->method('verify')->with($request);\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $event = new ControllerArgumentsEvent(\n            $kernel,\n            [new IsSignatureValidAttributeMethodsController(), 'withMultiple'],\n            [],\n            $request,\n            null\n        );\n\n        $listener = new IsSignatureValidAttributeListener($signer);\n        $listener->onKernelControllerArguments($event);\n    }\n\n    public function testValidationWithStringMethod()\n    {\n        $request = new Request([], [], [], [], [], ['REQUEST_METHOD' => 'POST']);\n\n        $signer = $this->createMock(UriSigner::class);\n        $signer->expects($this->once())->method('verify')->with($request);\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $event = new ControllerArgumentsEvent(\n            $kernel,\n            [new IsSignatureValidAttributeMethodsController(), 'withPostOnly'],\n            [],\n            $request,\n            null\n        );\n\n        $listener = new IsSignatureValidAttributeListener($signer);\n        $listener->onKernelControllerArguments($event);\n    }\n\n    public function testValidationWithArrayMethods()\n    {\n        $request = new Request([], [], [], [], [], ['REQUEST_METHOD' => 'POST']);\n\n        $signer = $this->createMock(UriSigner::class);\n        $signer->expects($this->once())->method('verify')->with($request);\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $event = new ControllerArgumentsEvent(\n            $kernel,\n            [new IsSignatureValidAttributeMethodsController(), 'withGetAndPost'],\n            [],\n            $request,\n            null\n        );\n\n        $listener = new IsSignatureValidAttributeListener($signer);\n        $listener->onKernelControllerArguments($event);\n    }\n\n    public function testValidationSkippedForNonMatchingMethod()\n    {\n        $request = new Request([], [], [], [], [], ['REQUEST_METHOD' => 'GET']);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $signer = $this->createMock(UriSigner::class);\n        $signer->expects($this->never())->method('verify');\n\n        $event = new ControllerArgumentsEvent(\n            $kernel,\n            [new IsSignatureValidAttributeMethodsController(), 'withPostOnly'],\n            [],\n            $request,\n            null\n        );\n\n        $listener = new IsSignatureValidAttributeListener($signer);\n        $listener->onKernelControllerArguments($event);\n    }\n}\n"
  },
  {
    "path": "Tests/EventListener/LocaleAwareListenerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\EventListener;\n\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpKernel\\Event\\FinishRequestEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\RequestEvent;\nuse Symfony\\Component\\HttpKernel\\EventListener\\LocaleAwareListener;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Contracts\\Translation\\LocaleAwareInterface;\n\nclass LocaleAwareListenerTest extends TestCase\n{\n    private LocaleAwareListener $listener;\n    private MockObject&LocaleAwareInterface $localeAwareService;\n    private RequestStack $requestStack;\n\n    protected function setUp(): void\n    {\n        $this->localeAwareService = $this->createMock(LocaleAwareInterface::class);\n        $this->requestStack = new RequestStack();\n        $this->listener = new LocaleAwareListener(new \\ArrayIterator([$this->localeAwareService]), $this->requestStack);\n    }\n\n    public function testLocaleIsSetInOnKernelRequest()\n    {\n        $this->localeAwareService\n            ->expects($this->once())\n            ->method('setLocale')\n            ->with($this->equalTo('fr'));\n\n        $event = new RequestEvent($this->createStub(HttpKernelInterface::class), $this->createRequest('fr'), HttpKernelInterface::MAIN_REQUEST);\n        $this->listener->onKernelRequest($event);\n    }\n\n    public function testDefaultLocaleIsUsedOnExceptionsInOnKernelRequest()\n    {\n        $this->localeAwareService\n            ->expects($this->exactly(2))\n            ->method('setLocale')\n            ->willReturnCallback(function (string $locale): void {\n                static $counter = 0;\n\n                if (1 === ++$counter) {\n                    throw new \\InvalidArgumentException();\n                }\n\n                $this->assertSame('en', $locale);\n            })\n        ;\n\n        $event = new RequestEvent($this->createStub(HttpKernelInterface::class), $this->createRequest('fr'), HttpKernelInterface::MAIN_REQUEST);\n        $this->listener->onKernelRequest($event);\n    }\n\n    public function testLocaleIsSetInOnKernelFinishRequestWhenParentRequestExists()\n    {\n        $this->localeAwareService\n            ->expects($this->once())\n            ->method('setLocale')\n            ->with($this->equalTo('fr'));\n\n        $this->requestStack->push($this->createRequest('fr'));\n        $this->requestStack->push($subRequest = $this->createRequest('de'));\n\n        $event = new FinishRequestEvent($this->createStub(HttpKernelInterface::class), $subRequest, HttpKernelInterface::SUB_REQUEST);\n        $this->listener->onKernelFinishRequest($event);\n    }\n\n    public function testLocaleIsSetToDefaultOnKernelFinishRequestWhenParentRequestDoesNotExist()\n    {\n        $this->localeAwareService\n            ->expects($this->once())\n            ->method('setLocale')\n            ->with($this->equalTo('en'));\n\n        $this->requestStack->push($subRequest = $this->createRequest('de'));\n\n        $event = new FinishRequestEvent($this->createStub(HttpKernelInterface::class), $subRequest, HttpKernelInterface::SUB_REQUEST);\n        $this->listener->onKernelFinishRequest($event);\n    }\n\n    public function testDefaultLocaleIsUsedOnExceptionsInOnKernelFinishRequest()\n    {\n        $this->localeAwareService\n            ->expects($this->exactly(2))\n            ->method('setLocale')\n            ->willReturnCallback(function (string $locale): void {\n                static $counter = 0;\n\n                if (1 === ++$counter) {\n                    throw new \\InvalidArgumentException();\n                }\n\n                $this->assertSame('en', $locale);\n            })\n        ;\n\n        $this->requestStack->push($this->createRequest('fr'));\n        $this->requestStack->push($subRequest = $this->createRequest('de'));\n\n        $event = new FinishRequestEvent($this->createStub(HttpKernelInterface::class), $subRequest, HttpKernelInterface::SUB_REQUEST);\n        $this->listener->onKernelFinishRequest($event);\n    }\n\n    private function createRequest(string $locale): Request\n    {\n        $request = new Request();\n        $request->setLocale($locale);\n\n        return $request;\n    }\n}\n"
  },
  {
    "path": "Tests/EventListener/LocaleListenerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\EventListener;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpKernel\\Event\\FinishRequestEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\RequestEvent;\nuse Symfony\\Component\\HttpKernel\\EventListener\\LocaleListener;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\nuse Symfony\\Component\\Routing\\RequestContext;\nuse Symfony\\Component\\Routing\\RequestContextAwareInterface;\nuse Symfony\\Component\\Routing\\Router;\n\nclass LocaleListenerTest extends TestCase\n{\n    public function testIsAnEventSubscriber()\n    {\n        $this->assertInstanceOf(EventSubscriberInterface::class, new LocaleListener(new RequestStack()));\n    }\n\n    public function testRegisteredEvent()\n    {\n        $this->assertEquals(\n            [\n                KernelEvents::REQUEST => [['setDefaultLocale', 100], ['onKernelRequest', 16]],\n                KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', 0]],\n            ],\n            LocaleListener::getSubscribedEvents()\n        );\n    }\n\n    public function testDefaultLocale()\n    {\n        $listener = new LocaleListener(new RequestStack(), 'fr');\n        $event = $this->getEvent($request = Request::create('/'));\n\n        $listener->setDefaultLocale($event);\n        $this->assertEquals('fr', $request->getLocale());\n    }\n\n    public function testLocaleFromRequestAttribute()\n    {\n        $request = Request::create('/');\n        $request->cookies->set(session_name(), 'value');\n\n        $request->attributes->set('_locale', 'es');\n        $listener = new LocaleListener(new RequestStack(), 'fr');\n        $event = $this->getEvent($request);\n\n        $listener->onKernelRequest($event);\n        $this->assertEquals('es', $request->getLocale());\n    }\n\n    public function testLocaleSetForRoutingContext()\n    {\n        // the request context is updated\n        $context = $this->createMock(RequestContext::class);\n        $context->expects($this->once())->method('setParameter')->with('_locale', 'es');\n\n        $router = $this->getMockBuilder(Router::class)->onlyMethods(['getContext'])->disableOriginalConstructor()->getMock();\n        $router->expects($this->once())->method('getContext')->willReturn($context);\n\n        $request = Request::create('/');\n\n        $request->attributes->set('_locale', 'es');\n        $listener = new LocaleListener(new RequestStack(), 'fr', $router);\n        $listener->onKernelRequest($this->getEvent($request));\n    }\n\n    public function testRouterResetWithParentRequestOnKernelFinishRequest()\n    {\n        // the request context is updated\n        $context = $this->createMock(RequestContext::class);\n        $context->expects($this->once())->method('setParameter')->with('_locale', 'es');\n\n        $router = $this->getMockBuilder(Router::class)->onlyMethods(['getContext'])->disableOriginalConstructor()->getMock();\n        $router->expects($this->once())->method('getContext')->willReturn($context);\n\n        $parentRequest = Request::create('/');\n        $parentRequest->setLocale('es');\n\n        $requestStack = new RequestStack();\n        $requestStack->push($parentRequest);\n\n        $subRequest = new Request();\n        $requestStack->push($subRequest);\n\n        $event = new FinishRequestEvent($this->createStub(HttpKernelInterface::class), new Request(), HttpKernelInterface::MAIN_REQUEST);\n\n        $listener = new LocaleListener($requestStack, 'fr', $router);\n        $listener->onKernelFinishRequest($event);\n    }\n\n    public function testRequestLocaleIsNotOverridden()\n    {\n        $request = Request::create('/');\n        $request->setLocale('de');\n        $listener = new LocaleListener(new RequestStack(), 'fr');\n        $event = $this->getEvent($request);\n\n        $listener->onKernelRequest($event);\n        $this->assertEquals('de', $request->getLocale());\n    }\n\n    public function testRequestPreferredLocaleFromAcceptLanguageHeader()\n    {\n        $request = Request::create('/');\n        $request->headers->set('Accept-Language', 'fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5');\n\n        $listener = new LocaleListener(new RequestStack(), 'de', null, true, ['de', 'fr']);\n        $event = $this->getEvent($request);\n\n        $listener->setDefaultLocale($event);\n        $listener->onKernelRequest($event);\n        $this->assertEquals('fr', $request->getLocale());\n    }\n\n    public function testRequestDefaultLocaleIfNoAcceptLanguageHeaderIsPresent()\n    {\n        $request = new Request();\n        $listener = new LocaleListener(new RequestStack(), 'de', null, true, ['lt', 'de']);\n        $event = $this->getEvent($request);\n\n        $listener->setDefaultLocale($event);\n        $listener->onKernelRequest($event);\n        $this->assertEquals('de', $request->getLocale());\n    }\n\n    public function testRequestVaryByLanguageAttributeIsSetIfUsingAcceptLanguageHeader()\n    {\n        $request = new Request();\n        $listener = new LocaleListener(new RequestStack(), 'de', null, true, ['lt', 'de']);\n        $event = $this->getEvent($request);\n\n        $listener->setDefaultLocale($event);\n        $listener->onKernelRequest($event);\n        $this->assertTrue($request->attributes->get('_vary_by_language'));\n    }\n\n    public function testRequestSecondPreferredLocaleFromAcceptLanguageHeader()\n    {\n        $request = Request::create('/');\n        $request->headers->set('Accept-Language', 'fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5');\n\n        $listener = new LocaleListener(new RequestStack(), 'de', null, true, ['de', 'en']);\n        $event = $this->getEvent($request);\n\n        $listener->setDefaultLocale($event);\n        $listener->onKernelRequest($event);\n        $this->assertEquals('en', $request->getLocale());\n    }\n\n    public function testDontUseAcceptLanguageHeaderIfNotEnabled()\n    {\n        $request = Request::create('/');\n        $request->headers->set('Accept-Language', 'fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5');\n\n        $listener = new LocaleListener(new RequestStack(), 'de', null, false, ['de', 'en']);\n        $event = $this->getEvent($request);\n\n        $listener->setDefaultLocale($event);\n        $listener->onKernelRequest($event);\n        $this->assertEquals('de', $request->getLocale());\n    }\n\n    public function testRequestUnavailablePreferredLocaleFromAcceptLanguageHeader()\n    {\n        $request = Request::create('/');\n        $request->headers->set('Accept-Language', 'fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5');\n\n        $listener = new LocaleListener(new RequestStack(), 'de', null, true, ['de', 'it']);\n        $event = $this->getEvent($request);\n\n        $listener->setDefaultLocale($event);\n        $listener->onKernelRequest($event);\n        $this->assertEquals('de', $request->getLocale());\n    }\n\n    public function testDefaultLocaleReturnedWhenNoAcceptLanguageMatchAndDefaultLocaleIsNotFirstEnabledLocale()\n    {\n        $request = Request::create('/');\n        $request->headers->set('Accept-Language', 'es;q=0.9,ja;q=0.8');\n\n        // 'de' is the default locale but is NOT first in enabled_locales\n        $listener = new LocaleListener(new RequestStack(), 'de', null, true, ['it', 'fr', 'de']);\n        $event = $this->getEvent($request);\n\n        $listener->setDefaultLocale($event);\n        $listener->onKernelRequest($event);\n        $this->assertEquals('de', $request->getLocale());\n    }\n\n    public function testRequestNoLocaleFromAcceptLanguageHeader()\n    {\n        $request = Request::create('/');\n        $request->headers->set('Accept-Language', 'fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5');\n\n        $listener = new LocaleListener(new RequestStack(), 'de', null, true);\n        $event = $this->getEvent($request);\n\n        $listener->setDefaultLocale($event);\n        $listener->onKernelRequest($event);\n        $this->assertEquals('fr_FR', $request->getLocale());\n    }\n\n    public function testRequestAttributeLocaleNotOverriddenFromAcceptLanguageHeader()\n    {\n        $request = Request::create('/');\n        $request->attributes->set('_locale', 'it');\n        $request->headers->set('Accept-Language', 'fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5');\n\n        $listener = new LocaleListener(new RequestStack(), 'de', null, true, ['fr', 'en']);\n        $event = $this->getEvent($request);\n\n        $listener->setDefaultLocale($event);\n        $listener->onKernelRequest($event);\n        $this->assertEquals('it', $request->getLocale());\n    }\n\n    public function testEnabledLocalesFiltersEmptyValues()\n    {\n        $request = Request::create('/');\n        $request->headers->set('Accept-Language', 'es,fr;q=0.8,en;q=0.5');\n\n        $listener = new LocaleListener(new RequestStack(), 'de', null, true, ['', null, 'en', 'fr']);\n        $event = $this->getEvent($request);\n\n        $listener->setDefaultLocale($event);\n        $listener->onKernelRequest($event);\n\n        $this->assertSame('fr', $request->getLocale());\n    }\n\n    public function testFinishRequestWithNoParentResetsRouterContextToDefault()\n    {\n        $context = new RequestContext();\n        $router = $this->createStub(RequestContextAwareInterface::class);\n        $router->method('getContext')->willReturn($context);\n\n        $request = Request::create('/');\n        $request->attributes->set('_locale', 'en');\n\n        $requestStack = new RequestStack();\n        $listener = new LocaleListener($requestStack, 'fr', $router);\n        $listener->onKernelRequest($this->getEvent($request));\n\n        $this->assertSame('en', $context->getParameter('_locale'));\n\n        $event = new FinishRequestEvent($this->createStub(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST);\n        $listener->onKernelFinishRequest($event);\n\n        $this->assertSame('fr', $context->getParameter('_locale'));\n    }\n\n    public function testSetDefaultLocaleSetsRouterContext()\n    {\n        $context = new RequestContext();\n        $router = $this->createStub(RequestContextAwareInterface::class);\n        $router->method('getContext')->willReturn($context);\n\n        $listener = new LocaleListener(new RequestStack(), 'fr', $router);\n        $request = Request::create('/');\n        $event = $this->getEvent($request);\n        $listener->setDefaultLocale($event);\n\n        $this->assertSame('fr', $context->getParameter('_locale'));\n    }\n\n    private function getEvent(Request $request): RequestEvent\n    {\n        return new RequestEvent($this->createStub(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST);\n    }\n}\n"
  },
  {
    "path": "Tests/EventListener/ProfilerListenerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\EventListener;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Event\\ExceptionEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\TerminateEvent;\nuse Symfony\\Component\\HttpKernel\\EventListener\\ProfilerListener;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\Kernel;\nuse Symfony\\Component\\HttpKernel\\Profiler\\Profile;\nuse Symfony\\Component\\HttpKernel\\Profiler\\Profiler;\n\nclass ProfilerListenerTest extends TestCase\n{\n    /**\n     * Test a main and sub request with an exception and `onlyException` profiler option enabled.\n     */\n    public function testKernelTerminate()\n    {\n        $profile = new Profile('token');\n\n        $profiler = $this->createMock(Profiler::class);\n        $profiler->expects($this->once())\n            ->method('collect')\n            ->willReturn($profile);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $mainRequest = new Request();\n        $subRequest = new Request();\n        $response = new Response();\n\n        $requestStack = new RequestStack();\n        $requestStack->push($mainRequest);\n\n        $onlyException = true;\n        $listener = new ProfilerListener($profiler, $requestStack, null, $onlyException);\n\n        // main request\n        $listener->onKernelResponse(new ResponseEvent($kernel, $mainRequest, Kernel::MAIN_REQUEST, $response));\n\n        // sub request\n        $listener->onKernelException(new ExceptionEvent($kernel, $subRequest, Kernel::SUB_REQUEST, new HttpException(404)));\n        $listener->onKernelResponse(new ResponseEvent($kernel, $subRequest, Kernel::SUB_REQUEST, $response));\n\n        $listener->onKernelTerminate(new TerminateEvent($kernel, $mainRequest, $response));\n    }\n\n    #[DataProvider('collectRequestProvider')]\n    public function testCollectParameter(Request $request, ?bool $enable)\n    {\n        $profile = new Profile('token');\n\n        $profiler = $this->createMock(Profiler::class);\n        $profiler->expects($this->once())\n            ->method('collect')\n            ->willReturn($profile);\n\n        $profiler\n            ->expects(null === $enable ? $this->never() : $this->once())\n            ->method($enable ? 'enable' : 'disable');\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $response = new Response();\n\n        $requestStack = new RequestStack();\n        $requestStack->push($request);\n\n        $listener = new ProfilerListener($profiler, $requestStack, null, false, false, 'profile');\n\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, Kernel::MAIN_REQUEST, $response));\n    }\n\n    public static function collectRequestProvider(): iterable\n    {\n        yield [Request::create('/'), null];\n        yield [Request::create('/', 'GET', ['profile' => '1']), true];\n        yield [Request::create('/', 'GET', ['profile' => '0']), false];\n\n        $request = Request::create('/');\n        $request->attributes->set('profile', true);\n        yield [$request, true];\n    }\n}\n"
  },
  {
    "path": "Tests/EventListener/ResponseListenerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\EventListener;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\EventDispatcher\\EventDispatcher;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\EventListener\\ResponseListener;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\n\nclass ResponseListenerTest extends TestCase\n{\n    private EventDispatcher $dispatcher;\n    private HttpKernelInterface $kernel;\n\n    protected function setUp(): void\n    {\n        $this->dispatcher = new EventDispatcher();\n        $listener = new ResponseListener('UTF-8');\n        $this->dispatcher->addListener(KernelEvents::RESPONSE, $listener->onKernelResponse(...));\n\n        $this->kernel = $this->createStub(HttpKernelInterface::class);\n    }\n\n    public function testFilterDoesNothingForSubRequests()\n    {\n        $response = new Response('foo');\n\n        $event = new ResponseEvent($this->kernel, new Request(), HttpKernelInterface::SUB_REQUEST, $response);\n        $this->dispatcher->dispatch($event, KernelEvents::RESPONSE);\n\n        $this->assertEquals('', $event->getResponse()->headers->get('content-type'));\n    }\n\n    public function testFilterSetsNonDefaultCharsetIfNotOverridden()\n    {\n        $listener = new ResponseListener('ISO-8859-15');\n        $this->dispatcher->addListener(KernelEvents::RESPONSE, $listener->onKernelResponse(...), 1);\n\n        $response = new Response('foo');\n\n        $event = new ResponseEvent($this->kernel, Request::create('/'), HttpKernelInterface::MAIN_REQUEST, $response);\n        $this->dispatcher->dispatch($event, KernelEvents::RESPONSE);\n\n        $this->assertEquals('ISO-8859-15', $response->getCharset());\n    }\n\n    public function testFilterDoesNothingIfCharsetIsOverridden()\n    {\n        $listener = new ResponseListener('ISO-8859-15');\n        $this->dispatcher->addListener(KernelEvents::RESPONSE, $listener->onKernelResponse(...), 1);\n\n        $response = new Response('foo');\n        $response->setCharset('ISO-8859-1');\n\n        $event = new ResponseEvent($this->kernel, Request::create('/'), HttpKernelInterface::MAIN_REQUEST, $response);\n        $this->dispatcher->dispatch($event, KernelEvents::RESPONSE);\n\n        $this->assertEquals('ISO-8859-1', $response->getCharset());\n    }\n\n    public function testFiltersSetsNonDefaultCharsetIfNotOverriddenOnNonTextContentType()\n    {\n        $listener = new ResponseListener('ISO-8859-15');\n        $this->dispatcher->addListener(KernelEvents::RESPONSE, $listener->onKernelResponse(...), 1);\n\n        $response = new Response('foo');\n        $request = Request::create('/');\n        $request->setRequestFormat('application/json');\n\n        $event = new ResponseEvent($this->kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response);\n        $this->dispatcher->dispatch($event, KernelEvents::RESPONSE);\n\n        $this->assertEquals('ISO-8859-15', $response->getCharset());\n    }\n\n    public function testSetContentLanguageHeaderWhenEmptyAndAtLeast2EnabledLocalesAreConfigured()\n    {\n        $listener = new ResponseListener('ISO-8859-15', true, ['fr', 'en']);\n        $this->dispatcher->addListener(KernelEvents::RESPONSE, $listener->onKernelResponse(...), 1);\n\n        $response = new Response('content');\n        $request = Request::create('/');\n        $request->setLocale('fr');\n\n        $event = new ResponseEvent($this->kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response);\n        $this->dispatcher->dispatch($event, KernelEvents::RESPONSE);\n\n        $this->assertEquals('fr', $response->headers->get('Content-Language'));\n    }\n\n    public function testNotOverrideContentLanguageHeaderWhenNotEmpty()\n    {\n        $listener = new ResponseListener('ISO-8859-15', true, ['de']);\n        $this->dispatcher->addListener(KernelEvents::RESPONSE, $listener->onKernelResponse(...), 1);\n\n        $response = new Response('content');\n        $response->headers->set('Content-Language', 'mi, en');\n        $request = Request::create('/');\n        $request->setLocale('de');\n\n        $event = new ResponseEvent($this->kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response);\n        $this->dispatcher->dispatch($event, KernelEvents::RESPONSE);\n\n        $this->assertEquals('mi, en', $response->headers->get('Content-Language'));\n    }\n\n    public function testNotSetContentLanguageHeaderWhenDisabled()\n    {\n        $listener = new ResponseListener('ISO-8859-15', false);\n        $this->dispatcher->addListener(KernelEvents::RESPONSE, $listener->onKernelResponse(...), 1);\n\n        $response = new Response('content');\n        $request = Request::create('/');\n        $request->setLocale('fr');\n\n        $event = new ResponseEvent($this->kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response);\n        $this->dispatcher->dispatch($event, KernelEvents::RESPONSE);\n\n        $this->assertNull($response->headers->get('Content-Language'));\n    }\n}\n"
  },
  {
    "path": "Tests/EventListener/RouterListenerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\EventListener;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\EventDispatcher\\EventDispatcher;\nuse Symfony\\Component\\HttpFoundation\\Exception\\BadRequestException;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerResolver;\nuse Symfony\\Component\\HttpKernel\\Event\\RequestEvent;\nuse Symfony\\Component\\HttpKernel\\EventListener\\ErrorListener;\nuse Symfony\\Component\\HttpKernel\\EventListener\\RouterListener;\nuse Symfony\\Component\\HttpKernel\\EventListener\\ValidateRequestListener;\nuse Symfony\\Component\\HttpKernel\\Exception\\BadRequestHttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\MethodNotAllowedHttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;\nuse Symfony\\Component\\HttpKernel\\HttpKernel;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\Routing\\Exception\\MethodNotAllowedException;\nuse Symfony\\Component\\Routing\\Exception\\NoConfigurationException;\nuse Symfony\\Component\\Routing\\Exception\\ResourceNotFoundException;\nuse Symfony\\Component\\Routing\\Matcher\\RequestMatcherInterface;\nuse Symfony\\Component\\Routing\\Matcher\\UrlMatcherInterface;\nuse Symfony\\Component\\Routing\\RequestContext;\n\nclass RouterListenerTest extends TestCase\n{\n    #[DataProvider('getPortData')]\n    public function testPort($defaultHttpPort, $defaultHttpsPort, $uri, $expectedHttpPort, $expectedHttpsPort)\n    {\n        $urlMatcher = $this->createStub(UrlMatcherInterface::class);\n\n        $context = new RequestContext();\n        $context->setHttpPort($defaultHttpPort);\n        $context->setHttpsPort($defaultHttpsPort);\n        $urlMatcher\n            ->method('getContext')\n            ->willReturn($context);\n\n        $listener = new RouterListener($urlMatcher, new RequestStack());\n        $event = $this->createRequestEventForUri($uri);\n        $listener->onKernelRequest($event);\n\n        $this->assertEquals($expectedHttpPort, $context->getHttpPort());\n        $this->assertEquals($expectedHttpsPort, $context->getHttpsPort());\n        $this->assertEquals(str_starts_with($uri, 'https') ? 'https' : 'http', $context->getScheme());\n    }\n\n    public static function getPortData()\n    {\n        return [\n            [80, 443, 'http://localhost/', 80, 443],\n            [80, 443, 'http://localhost:90/', 90, 443],\n            [80, 443, 'https://localhost/', 80, 443],\n            [80, 443, 'https://localhost:90/', 80, 90],\n        ];\n    }\n\n    private function createRequestEventForUri(string $uri): RequestEvent\n    {\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $request = Request::create($uri);\n        $request->attributes->set('_controller', null); // Prevents going in to routing process\n\n        return new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST);\n    }\n\n    public function testRequestMatcher()\n    {\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $request = Request::create('http://localhost/');\n        $event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $requestMatcher = $this->createMock(RequestMatcherInterface::class);\n        $requestMatcher->expects($this->once())\n                       ->method('matchRequest')\n                       ->with($this->isInstanceOf(Request::class))\n                       ->willReturn([]);\n\n        $listener = new RouterListener($requestMatcher, new RequestStack(), new RequestContext());\n        $listener->onKernelRequest($event);\n    }\n\n    public function testSubRequestWithDifferentMethod()\n    {\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $request = Request::create('http://localhost/', 'post');\n        $event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $requestMatcher = $this->createStub(RequestMatcherInterface::class);\n        $requestMatcher\n            ->method('matchRequest')\n            ->willReturn([]);\n\n        $context = new RequestContext();\n\n        $listener = new RouterListener($requestMatcher, new RequestStack(), new RequestContext());\n        $listener->onKernelRequest($event);\n\n        // sub-request with another HTTP method\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $request = Request::create('http://localhost/', 'get');\n        $event = new RequestEvent($kernel, $request, HttpKernelInterface::SUB_REQUEST);\n\n        $listener->onKernelRequest($event);\n\n        $this->assertEquals('GET', $context->getMethod());\n    }\n\n    #[DataProvider('getLoggingParameterData')]\n    public function testLoggingParameter($parameter, $log, $parameters)\n    {\n        $requestMatcher = $this->createMock(RequestMatcherInterface::class);\n        $requestMatcher->expects($this->once())\n            ->method('matchRequest')\n            ->willReturn($parameter);\n\n        $logger = $this->createMock(LoggerInterface::class);\n        $logger->expects($this->once())\n            ->method('info')\n            ->with($this->equalTo($log), $this->equalTo($parameters));\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $request = Request::create('http://localhost/');\n\n        $listener = new RouterListener($requestMatcher, new RequestStack(), new RequestContext(), $logger);\n        $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));\n    }\n\n    public static function getLoggingParameterData()\n    {\n        return [\n            [['_route' => 'foo'], 'Matched route \"{route}\".', ['route' => 'foo', 'route_parameters' => ['_route' => 'foo'], 'request_uri' => 'http://localhost/', 'method' => 'GET']],\n            [[], 'Matched route \"{route}\".', ['route' => 'n/a', 'route_parameters' => [], 'request_uri' => 'http://localhost/', 'method' => 'GET']],\n        ];\n    }\n\n    public function testWithBadRequest()\n    {\n        $requestStack = new RequestStack();\n\n        $requestMatcher = $this->createMock(RequestMatcherInterface::class);\n        $requestMatcher->expects($this->never())->method('matchRequest');\n\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addSubscriber(new ValidateRequestListener());\n        $dispatcher->addSubscriber(new RouterListener($requestMatcher, $requestStack, new RequestContext()));\n        $dispatcher->addSubscriber(new ErrorListener(static fn () => new Response('Exception handled', 400)));\n\n        $kernel = new HttpKernel($dispatcher, new ControllerResolver(), $requestStack, new ArgumentResolver());\n\n        $request = Request::create('http://localhost/');\n        $request->headers->set('host', '###');\n        $response = $kernel->handle($request);\n        $this->assertSame(400, $response->getStatusCode());\n    }\n\n    public function testNoRoutingConfigurationResponse()\n    {\n        $requestStack = new RequestStack();\n\n        $requestMatcher = $this->createMock(RequestMatcherInterface::class);\n        $requestMatcher\n            ->expects($this->exactly(2))\n            ->method('matchRequest')\n            ->willThrowException(new NoConfigurationException())\n        ;\n\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addSubscriber(new RouterListener($requestMatcher, $requestStack, new RequestContext()));\n\n        $kernel = new HttpKernel($dispatcher, new ControllerResolver(), $requestStack, new ArgumentResolver());\n\n        $request = Request::create('http://localhost/');\n\n        $response = $kernel->handle($request);\n        $this->assertSame(404, $response->getStatusCode());\n        $this->assertStringContainsString('Welcome', $response->getContent());\n\n        $response = $kernel->handle($request);\n        $this->assertSame(404, $response->getStatusCode());\n        $this->assertStringContainsString('Welcome', $response->getContent());\n    }\n\n    public function testRequestWithBadHost()\n    {\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $request = Request::create('/');\n        $request->headers->set('host', 'bad host %22');\n        $event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $requestMatcher = $this->createStub(RequestMatcherInterface::class);\n\n        $listener = new RouterListener($requestMatcher, new RequestStack(), new RequestContext());\n        try {\n            $listener->onKernelRequest($event);\n            self::fail(\\sprintf('Expected \"%s\" or \"%s\" to be thrown.', BadRequestHttpException::class, BadRequestException::class));\n        } catch (\\Throwable $e) {\n            $this->assertTrue($e instanceof BadRequestHttpException || $e instanceof BadRequestException);\n        }\n    }\n\n    public function testResourceNotFoundException()\n    {\n        $this->expectException(NotFoundHttpException::class);\n        $this->expectExceptionMessage('No route found for \"GET https://www.symfony.com/path\" (from \"https://www.google.com\")');\n\n        $context = new RequestContext();\n\n        $urlMatcher = $this->createStub(UrlMatcherInterface::class);\n\n        $urlMatcher\n            ->method('getContext')\n            ->willReturn($context);\n\n        $urlMatcher\n            ->method('match')\n            ->willThrowException(new ResourceNotFoundException());\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $request = Request::create('https://www.symfony.com/path');\n        $request->headers->set('referer', 'https://www.google.com');\n\n        $event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $listener = new RouterListener($urlMatcher, new RequestStack());\n        $listener->onKernelRequest($event);\n    }\n\n    public function testMethodNotAllowedException()\n    {\n        $this->expectException(MethodNotAllowedHttpException::class);\n        $this->expectExceptionMessage('No route found for \"GET https://www.symfony.com/path\": Method Not Allowed (Allow: POST)');\n\n        $context = new RequestContext();\n\n        $urlMatcher = $this->createStub(UrlMatcherInterface::class);\n\n        $urlMatcher\n            ->method('getContext')\n            ->willReturn($context);\n\n        $urlMatcher\n            ->method('match')\n            ->willThrowException(new MethodNotAllowedException(['POST']));\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $request = Request::create('https://www.symfony.com/path');\n\n        $event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $listener = new RouterListener($urlMatcher, new RequestStack());\n        $listener->onKernelRequest($event);\n    }\n\n    #[DataProvider('provideRouteMapping')]\n    public function testRouteMapping(array $expected, array $parameters)\n    {\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $request = Request::create('http://localhost/');\n        $event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $requestMatcher = $this->createStub(RequestMatcherInterface::class);\n        $requestMatcher\n            ->method('matchRequest')\n            ->willReturn($parameters);\n\n        $listener = new RouterListener($requestMatcher, new RequestStack(), new RequestContext());\n        $listener->onKernelRequest($event);\n\n        $expected['_route_mapping'] = $parameters['_route_mapping'];\n        unset($parameters['_route_mapping']);\n        $expected['_route_params'] = $parameters;\n\n        $this->assertEquals($expected, $request->attributes->all());\n    }\n\n    public static function provideRouteMapping(): iterable\n    {\n        yield [\n            [\n                'conference' => 'vienna-2024',\n            ],\n            [\n                'slug' => 'vienna-2024',\n                '_route_mapping' => [\n                    'slug' => 'conference',\n                ],\n            ],\n        ];\n\n        yield [\n            [\n                'article' => [\n                    'id' => 'abc123',\n                    'date' => '2024-04-24',\n                    'slug' => 'symfony-rocks',\n                ],\n            ],\n            [\n                'id' => 'abc123',\n                'date' => '2024-04-24',\n                'slug' => 'symfony-rocks',\n                '_route_mapping' => [\n                    'id' => 'article',\n                    'date' => 'article',\n                    'slug' => 'article',\n                ],\n            ],\n        ];\n\n        yield [\n            [\n                'conference' => ['slug' => 'vienna-2024'],\n            ],\n            [\n                'slug' => 'vienna-2024',\n                '_route_mapping' => [\n                    'slug' => [\n                        'conference',\n                        'slug',\n                    ],\n                ],\n            ],\n        ];\n\n        yield [\n            [\n                'article' => [\n                    'id' => 'abc123',\n                    'date' => '2024-04-24',\n                    'slug' => 'symfony-rocks',\n                ],\n            ],\n            [\n                'id' => 'abc123',\n                'date' => '2024-04-24',\n                'slug' => 'symfony-rocks',\n                '_route_mapping' => [\n                    'id' => [\n                        'article',\n                        'id',\n                    ],\n                    'date' => [\n                        'article',\n                        'date',\n                    ],\n                    'slug' => [\n                        'article',\n                        'slug',\n                    ],\n                ],\n            ],\n        ];\n    }\n}\n"
  },
  {
    "path": "Tests/EventListener/SerializeControllerResultListenerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\EventListener;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Attribute\\Serialize;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerArgumentsMetadata;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerAttributeEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ControllerEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ViewEvent;\nuse Symfony\\Component\\HttpKernel\\EventListener\\SerializeControllerResultAttributeListener;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\Serializer\\SerializerInterface;\n\nclass SerializeControllerResultListenerTest extends TestCase\n{\n    public function testSerializeAttribute()\n    {\n        $controllerResult = new ProductCreated(10);\n        $responseBody = '{\"productId\": 10}';\n\n        $serializer = $this->createMock(SerializerInterface::class);\n        $serializer->expects($this->once())\n            ->method('serialize')\n            ->with($controllerResult, 'json', ['foo' => 'bar'])\n            ->willReturn($responseBody);\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $request = new Request();\n\n        $controller = new GetApiController();\n        $requestType = HttpKernelInterface::MAIN_REQUEST;\n        $viewEvent = new ViewEvent(\n            $kernel,\n            $request,\n            $requestType,\n            $controllerResult,\n            new ControllerArgumentsMetadata(\n                new ControllerEvent($kernel, $controller, $request, $requestType),\n                new ControllerArgumentsEvent(\n                    $kernel,\n                    $controller,\n                    [],\n                    $request,\n                    $requestType,\n                ),\n            ),\n        );\n\n        $listener = new SerializeControllerResultAttributeListener($serializer);\n        $listener->onView(new ControllerAttributeEvent(new Serialize(201, ['X-Test-Header' => 'abc'], ['foo' => 'bar']), $viewEvent));\n\n        $response = $viewEvent->getResponse();\n\n        self::assertSame(201, $response->getStatusCode());\n        self::assertSame($responseBody, $response->getContent());\n        self::assertSame('abc', $response->headers->get('X-Test-Header'));\n    }\n}\n\nclass ProductCreated\n{\n    public function __construct(public readonly int $productId)\n    {\n    }\n}\n\nclass GetApiController\n{\n    #[Serialize(201, ['X-Test-Header' => 'abc'], ['foo' => 'bar'])]\n    public function __invoke(): ProductCreated\n    {\n        return new ProductCreated(10);\n    }\n}\n"
  },
  {
    "path": "Tests/EventListener/SessionListenerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\EventListener;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\Attributes\\RunInSeparateProcess;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\DependencyInjection\\Container;\nuse Symfony\\Component\\DependencyInjection\\ServiceLocator;\nuse Symfony\\Component\\HttpFoundation\\Cookie;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpFoundation\\Session\\Session;\nuse Symfony\\Component\\HttpFoundation\\Session\\SessionFactory;\nuse Symfony\\Component\\HttpFoundation\\Session\\SessionInterface;\nuse Symfony\\Component\\HttpFoundation\\Session\\Storage\\NativeSessionStorage;\nuse Symfony\\Component\\HttpFoundation\\Session\\Storage\\NativeSessionStorageFactory;\nuse Symfony\\Component\\HttpFoundation\\Session\\Storage\\PhpBridgeSessionStorageFactory;\nuse Symfony\\Component\\HttpFoundation\\Session\\Storage\\SessionStorageFactoryInterface;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\RequestDataCollector;\nuse Symfony\\Component\\HttpKernel\\Event\\RequestEvent;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\EventListener\\AbstractSessionListener;\nuse Symfony\\Component\\HttpKernel\\EventListener\\SessionListener;\nuse Symfony\\Component\\HttpKernel\\Exception\\UnexpectedSessionUsageException;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\KernelInterface;\n\nclass SessionListenerTest extends TestCase\n{\n    #[DataProvider('provideSessionOptions')]\n    #[RunInSeparateProcess]\n    public function testSessionCookieOptions(array $phpSessionOptions, array $sessionOptions, array $expectedSessionOptions)\n    {\n        $session = $this->createStub(Session::class);\n        $session->method('getUsageIndex')->willReturn(0, 1);\n        $session->method('getId')->willReturn('123456');\n        $session->method('getName')->willReturn('PHPSESSID');\n        $session->method('save');\n        $session->method('isStarted')->willReturn(true);\n\n        if (isset($phpSessionOptions['samesite'])) {\n            ini_set('session.cookie_samesite', $phpSessionOptions['samesite']);\n        }\n        session_set_cookie_params(0, $phpSessionOptions['path'] ?? null, $phpSessionOptions['domain'] ?? null, $phpSessionOptions['secure'] ?? null, $phpSessionOptions['httponly'] ?? null);\n\n        $listener = new SessionListener(new Container(), false, $sessionOptions);\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $request = new Request();\n        $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));\n\n        $request->setSession($session);\n        $response = new Response();\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));\n\n        $cookies = $response->headers->getCookies();\n\n        if ($sessionOptions['use_cookies'] ?? true) {\n            $this->assertCount(1, $cookies);\n            $this->assertSame('PHPSESSID', $cookies[0]->getName());\n            $this->assertSame('123456', $cookies[0]->getValue());\n            $this->assertSame($expectedSessionOptions['cookie_path'], $cookies[0]->getPath());\n            $this->assertSame($expectedSessionOptions['cookie_domain'], $cookies[0]->getDomain());\n            $this->assertSame($expectedSessionOptions['cookie_secure'], $cookies[0]->isSecure());\n            $this->assertSame($expectedSessionOptions['cookie_httponly'], $cookies[0]->isHttpOnly());\n            $this->assertSame($expectedSessionOptions['cookie_samesite'], $cookies[0]->getSameSite());\n        } else {\n            $this->assertCount(0, $cookies);\n        }\n    }\n\n    public static function provideSessionOptions(): \\Generator\n    {\n        yield 'set_samesite_by_php' => [\n            'phpSessionOptions' => ['samesite' => Cookie::SAMESITE_STRICT],\n            'sessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true],\n            'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_STRICT],\n        ];\n\n        yield 'set_cookie_path_by_php' => [\n            'phpSessionOptions' => ['path' => '/prod/'],\n            'sessionOptions' => ['cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],\n            'expectedSessionOptions' => ['cookie_path' => '/prod/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],\n        ];\n\n        yield 'set_cookie_secure_by_php' => [\n            'phpSessionOptions' => ['secure' => true],\n            'sessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],\n            'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],\n        ];\n\n        yield 'set_cookiesecure_auto_by_symfony_false_by_php' => [\n            'phpSessionOptions' => ['secure' => false],\n            'sessionOptions' => ['cookie_path' => '/test/', 'cookie_httponly' => true, 'cookie_secure' => 'auto', 'cookie_samesite' => Cookie::SAMESITE_LAX],\n            'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => false, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],\n        ];\n\n        yield 'set_cookiesecure_auto_by_symfony_true_by_php' => [\n            'phpSessionOptions' => ['secure' => true],\n            'sessionOptions' => ['cookie_path' => '/test/', 'cookie_httponly' => true, 'cookie_secure' => 'auto', 'cookie_samesite' => Cookie::SAMESITE_LAX],\n            'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],\n        ];\n\n        yield 'set_cookie_httponly_by_php' => [\n            'phpSessionOptions' => ['httponly' => true],\n            'sessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],\n            'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],\n        ];\n\n        yield 'set_cookie_domain_by_php' => [\n            'phpSessionOptions' => ['domain' => 'test.symfony'],\n            'sessionOptions' => ['cookie_path' => '/test/', 'cookie_httponly' => true, 'cookie_secure' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],\n            'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => 'test.symfony', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],\n        ];\n\n        yield 'set_samesite_by_symfony' => [\n            'phpSessionOptions' => ['samesite' => Cookie::SAMESITE_STRICT],\n            'sessionOptions' => ['cookie_path' => '/test/', 'cookie_httponly' => true, 'cookie_secure' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],\n            'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],\n        ];\n\n        yield 'set_use_cookies_false_by_symfony' => [\n            'phpSessionOptions' => [],\n            'sessionOptions' => ['use_cookies' => false, 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],\n            'expectedSessionOptions' => [],\n        ];\n    }\n\n    #[RunInSeparateProcess]\n    public function testPhpBridgeAlreadyStartedSession()\n    {\n        session_start();\n        $sessionId = session_id();\n\n        $request = new Request();\n        $listener = $this->createListener($request, new PhpBridgeSessionStorageFactory());\n\n        $event = new RequestEvent($this->createStub(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $listener->onKernelRequest($event);\n\n        $this->assertTrue($request->hasSession());\n        $this->assertSame($sessionId, $request->getSession()->getId());\n    }\n\n    #[RunInSeparateProcess]\n    public function testSessionCookieWrittenNoCookieGiven()\n    {\n        $request = new Request();\n        $listener = $this->createListener($request, new NativeSessionStorageFactory());\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));\n        $session = $request->getSession();\n        $session->set('hello', 'world');\n\n        $response = new Response();\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));\n\n        $cookies = $response->headers->getCookies();\n        $this->assertCount(1, $cookies);\n        $sessionCookie = $cookies[0];\n\n        $this->assertSame('PHPSESSID', $sessionCookie->getName());\n        $this->assertNotEmpty($sessionCookie->getValue());\n        $this->assertFalse($sessionCookie->isCleared());\n    }\n\n    #[RunInSeparateProcess]\n    public function testSessionCookieNotWrittenCookieGiven()\n    {\n        $sessionId = $this->createValidSessionId();\n\n        $this->assertNotEmpty($sessionId);\n\n        $request = new Request();\n        $request->cookies->set('PHPSESSID', $sessionId);\n\n        $listener = $this->createListener($request, new NativeSessionStorageFactory());\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));\n\n        $session = $request->getSession();\n        $this->assertSame($sessionId, $session->getId());\n        $session->set('hello', 'world');\n\n        $response = new Response();\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));\n        $this->assertSame($sessionId, $session->getId());\n\n        $cookies = $response->headers->getCookies();\n        $this->assertCount(0, $cookies);\n    }\n\n    #[RunInSeparateProcess]\n    public function testNewSessionIdIsNotOverwritten()\n    {\n        $newSessionId = $this->createValidSessionId();\n\n        $this->assertNotEmpty($newSessionId);\n\n        $request = new Request();\n        $request->cookies->set('PHPSESSID', 'OLD-SESSION-ID');\n\n        $listener = $this->createListener($request, new NativeSessionStorageFactory());\n\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));\n\n        $session = $request->getSession();\n        $this->assertSame($newSessionId, $session->getId());\n        $session->set('hello', 'world');\n\n        $response = new Response();\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));\n        $this->assertSame($newSessionId, $session->getId());\n\n        $cookies = $response->headers->getCookies();\n\n        $this->assertCount(1, $cookies);\n        $sessionCookie = $cookies[0];\n\n        $this->assertSame('PHPSESSID', $sessionCookie->getName());\n        $this->assertSame($newSessionId, $sessionCookie->getValue());\n    }\n\n    #[RunInSeparateProcess]\n    public function testSessionCookieClearedWhenInvalidated()\n    {\n        $sessionId = $this->createValidSessionId();\n        $request = new Request();\n        $request->cookies->set('PHPSESSID', $sessionId);\n        $listener = $this->createListener($request, new NativeSessionStorageFactory());\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));\n\n        $session = $request->getSession();\n        $session->start();\n        $sessionId = $session->getId();\n        $this->assertNotEmpty($sessionId);\n        $_SESSION['hello'] = 'world'; // check compatibility to php session bridge\n\n        $session->invalidate();\n\n        $response = new Response();\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));\n\n        $cookies = $response->headers->getCookies();\n        $this->assertCount(1, $cookies);\n        $sessionCookie = $cookies[0];\n\n        $this->assertSame('PHPSESSID', $sessionCookie->getName());\n        $this->assertTrue($sessionCookie->isCleared());\n    }\n\n    #[RunInSeparateProcess]\n    public function testSessionCookieNotClearedWhenOtherVariablesSet()\n    {\n        $sessionId = $this->createValidSessionId();\n        $request = new Request();\n        $request->cookies->set('PHPSESSID', $sessionId);\n        $listener = $this->createListener($request, new NativeSessionStorageFactory());\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));\n\n        $session = $request->getSession();\n        $session->start();\n        $sessionId = $session->getId();\n        $this->assertNotEmpty($sessionId);\n        $_SESSION['hello'] = 'world';\n\n        $response = new Response();\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));\n\n        $cookies = $response->headers->getCookies();\n        $this->assertCount(0, $cookies);\n    }\n\n    #[RunInSeparateProcess]\n    public function testSessionCookieSetWhenOtherNativeVariablesSet()\n    {\n        $request = new Request();\n        $listener = $this->createListener($request, new NativeSessionStorageFactory());\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));\n\n        $session = $request->getSession();\n        $session->start();\n        $sessionId = $session->getId();\n        $this->assertNotEmpty($sessionId);\n        $_SESSION['hello'] = 'world';\n\n        $response = new Response();\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));\n\n        $cookies = $response->headers->getCookies();\n        $this->assertCount(1, $cookies);\n        $sessionCookie = $cookies[0];\n\n        $this->assertSame('PHPSESSID', $sessionCookie->getName());\n        $this->assertNotEmpty($sessionCookie->getValue());\n        $this->assertFalse($sessionCookie->isCleared());\n    }\n\n    public function testOnlyTriggeredOnMainRequest()\n    {\n        $listener = new class extends AbstractSessionListener {\n            protected function getSession(): ?SessionInterface\n            {\n                return null;\n            }\n        };\n\n        $event = $this->createMock(RequestEvent::class);\n        $event->expects($this->once())->method('isMainRequest')->willReturn(false);\n        $event->expects($this->never())->method('getRequest');\n\n        // sub request\n        $listener->onKernelRequest($event);\n    }\n\n    public function testSessionIsSet()\n    {\n        $session = $this->createMock(Session::class);\n        $session->expects($this->exactly(1))->method('getName')->willReturn('PHPSESSID');\n        $sessionFactory = $this->createMock(SessionFactory::class);\n        $sessionFactory->expects($this->once())->method('createSession')->willReturn($session);\n\n        $sessionStorage = $this->createMock(NativeSessionStorage::class);\n        $sessionStorage->expects($this->never())->method('setOptions')->with(['cookie_secure' => true]);\n\n        $container = new Container();\n        $container->set('session_factory', $sessionFactory);\n        $container->set('request_stack', new RequestStack());\n\n        $request = new Request();\n        $listener = new SessionListener($container);\n\n        $event = new RequestEvent($this->createStub(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $listener->onKernelRequest($event);\n\n        $this->assertTrue($request->hasSession());\n        $this->assertSame($session, $request->getSession());\n    }\n\n    public function testSessionUsesFactory()\n    {\n        $session = $this->createMock(Session::class);\n        $session->expects($this->exactly(1))->method('getName')->willReturn('PHPSESSID');\n        $sessionFactory = $this->createMock(SessionFactory::class);\n        $sessionFactory->expects($this->once())->method('createSession')->willReturn($session);\n\n        $container = new Container();\n        $container->set('session_factory', $sessionFactory);\n\n        $request = new Request();\n        $listener = new SessionListener($container);\n\n        $event = new RequestEvent($this->createStub(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $listener->onKernelRequest($event);\n\n        $this->assertTrue($request->hasSession());\n        $this->assertSame($session, $request->getSession());\n    }\n\n    public function testUsesFactoryWhenNeeded()\n    {\n        $session = $this->createMock(Session::class);\n        $session->expects($this->once())->method('getName')->willReturn('foo');\n        $sessionFactory = $this->createMock(SessionFactory::class);\n        $sessionFactory->expects($this->once())->method('createSession')->willReturn($session);\n\n        $container = new Container();\n        $container->set('session_factory', $sessionFactory);\n\n        $request = new Request();\n        $listener = new SessionListener($container);\n\n        $event = new RequestEvent($this->createStub(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST);\n        $listener->onKernelRequest($event);\n\n        $request->getSession();\n\n        $event = new ResponseEvent($this->createStub(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST, new Response());\n        $listener->onKernelResponse($event);\n    }\n\n    public function testDontUsesFactoryWhenSessionIsNotUsed()\n    {\n        $sessionFactory = $this->createMock(SessionFactory::class);\n        $sessionFactory->expects($this->never())->method('createSession');\n\n        $container = new Container();\n        $container->set('session_factory', $sessionFactory);\n\n        $request = new Request();\n        $listener = new SessionListener($container);\n\n        $event = new RequestEvent($this->createStub(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST);\n        $listener->onKernelRequest($event);\n\n        $event = new ResponseEvent($this->createStub(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST, new Response());\n        $listener->onKernelResponse($event);\n    }\n\n    public function testResponseIsPrivateIfSessionStarted()\n    {\n        $session = $this->createMock(Session::class);\n        $session->expects($this->once())->method('getUsageIndex')->willReturn(1);\n        $session->expects($this->once())->method('getName')->willReturn('foo');\n        $sessionFactory = $this->createMock(SessionFactory::class);\n        $sessionFactory->expects($this->once())->method('createSession')->willReturn($session);\n\n        $container = new Container();\n        $container->set('session_factory', $sessionFactory);\n\n        $listener = new SessionListener($container);\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $request = new Request();\n        $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));\n\n        $request->getSession();\n\n        $response = new Response();\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));\n\n        $this->assertTrue($response->headers->has('Expires'));\n        $this->assertTrue($response->headers->hasCacheControlDirective('private'));\n        $this->assertTrue($response->headers->hasCacheControlDirective('must-revalidate'));\n        $this->assertSame('0', $response->headers->getCacheControlDirective('max-age'));\n        $this->assertLessThanOrEqual(new \\DateTimeImmutable('now', new \\DateTimeZone('UTC')), new \\DateTimeImmutable($response->headers->get('Expires')));\n        $this->assertFalse($response->headers->has(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER));\n    }\n\n    public function testResponseIsStillPublicIfSessionStartedAndHeaderPresent()\n    {\n        $session = $this->createMock(Session::class);\n        $session->expects($this->once())->method('getUsageIndex')->willReturn(1);\n\n        $container = new Container();\n\n        $listener = new SessionListener($container);\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $request = new Request();\n        $request->setSession($session);\n        $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));\n\n        $response = new Response();\n        $response->setSharedMaxAge(60);\n        $response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true');\n\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));\n\n        $this->assertTrue($response->headers->hasCacheControlDirective('public'));\n        $this->assertFalse($response->headers->has('Expires'));\n        $this->assertFalse($response->headers->hasCacheControlDirective('private'));\n        $this->assertFalse($response->headers->hasCacheControlDirective('must-revalidate'));\n        $this->assertSame('60', $response->headers->getCacheControlDirective('s-maxage'));\n        $this->assertFalse($response->headers->has(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER));\n    }\n\n    public function testSessionSaveAndResponseHasSessionCookie()\n    {\n        $session = $this->getMockBuilder(Session::class)->disableOriginalConstructor()->getMock();\n        $session->expects($this->exactly(1))->method('getUsageIndex')->willReturn(0);\n        $session->expects($this->exactly(1))->method('getId')->willReturn('123456');\n        $session->expects($this->exactly(1))->method('getName')->willReturn('PHPSESSID');\n        $session->expects($this->exactly(1))->method('save');\n        $session->expects($this->exactly(1))->method('isStarted')->willReturn(true);\n\n        $container = new Container();\n\n        $listener = new SessionListener($container);\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $request = new Request();\n        $request->setSession($session);\n        $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));\n\n        $response = new Response();\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));\n\n        $cookies = $response->headers->getCookies();\n        $this->assertCount(1, $cookies);\n        $this->assertSame('PHPSESSID', $cookies[0]->getName());\n        $this->assertSame('123456', $cookies[0]->getValue());\n    }\n\n    public function testUninitializedSessionUsingSessionFromRequest()\n    {\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $response = new Response();\n        $response->setSharedMaxAge(60);\n        $response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true');\n\n        $request = new Request();\n        $request->setSession(new Session());\n\n        $listener = new SessionListener(new Container());\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));\n        $this->assertFalse($response->headers->has('Expires'));\n        $this->assertTrue($response->headers->hasCacheControlDirective('public'));\n        $this->assertFalse($response->headers->hasCacheControlDirective('private'));\n        $this->assertFalse($response->headers->hasCacheControlDirective('must-revalidate'));\n        $this->assertSame('60', $response->headers->getCacheControlDirective('s-maxage'));\n        $this->assertFalse($response->headers->has(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER));\n    }\n\n    public function testUninitializedSessionWithoutInitializedSession()\n    {\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $response = new Response();\n        $response->setSharedMaxAge(60);\n        $response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true');\n\n        $container = new ServiceLocator([]);\n\n        $listener = new SessionListener($container);\n        $listener->onKernelResponse(new ResponseEvent($kernel, new Request(), HttpKernelInterface::MAIN_REQUEST, $response));\n        $this->assertFalse($response->headers->has('Expires'));\n        $this->assertTrue($response->headers->hasCacheControlDirective('public'));\n        $this->assertFalse($response->headers->hasCacheControlDirective('private'));\n        $this->assertFalse($response->headers->hasCacheControlDirective('must-revalidate'));\n        $this->assertSame('60', $response->headers->getCacheControlDirective('s-maxage'));\n    }\n\n    public function testResponseHeadersMaxAgeAndExpiresNotBeOverriddenIfSessionStarted()\n    {\n        $session = $this->createMock(Session::class);\n        $session->expects($this->once())->method('getUsageIndex')->willReturn(1);\n        $session->expects($this->once())->method('getName')->willReturn('foo');\n        $sessionFactory = $this->createMock(SessionFactory::class);\n        $sessionFactory->expects($this->once())->method('createSession')->willReturn($session);\n\n        $container = new Container();\n        $container->set('session_factory', $sessionFactory);\n\n        $listener = new SessionListener($container);\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $request = new Request();\n        $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));\n\n        $request->getSession();\n\n        $response = new Response();\n        $response->setPrivate();\n        $expiresHeader = gmdate('D, d M Y H:i:s', time() + 600).' GMT';\n        $response->setMaxAge(600);\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));\n\n        $this->assertTrue($response->headers->has('expires'));\n        $this->assertSame($expiresHeader, $response->headers->get('expires'));\n        $this->assertFalse($response->headers->has('max-age'));\n        $this->assertSame('600', $response->headers->getCacheControlDirective('max-age'));\n        $this->assertFalse($response->headers->hasCacheControlDirective('public'));\n        $this->assertTrue($response->headers->hasCacheControlDirective('private'));\n        $this->assertTrue($response->headers->hasCacheControlDirective('must-revalidate'));\n        $this->assertFalse($response->headers->has(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER));\n    }\n\n    public function testResponseHeadersMaxAgeAndExpiresDefaultValuesIfSessionStarted()\n    {\n        $session = $this->createMock(Session::class);\n        $session->expects($this->once())->method('getUsageIndex')->willReturn(1);\n\n        $container = new Container();\n\n        $listener = new SessionListener($container);\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $request = new Request();\n        $request->setSession($session);\n        $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));\n\n        $response = new Response();\n        $expiresHeader = gmdate('D, d M Y H:i:s', time()).' GMT';\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));\n\n        $this->assertTrue($response->headers->has('expires'));\n        $this->assertSame($expiresHeader, $response->headers->get('expires'));\n        $this->assertFalse($response->headers->has('max-age'));\n        $this->assertSame('0', $response->headers->getCacheControlDirective('max-age'));\n        $this->assertFalse($response->headers->hasCacheControlDirective('public'));\n        $this->assertTrue($response->headers->hasCacheControlDirective('private'));\n        $this->assertTrue($response->headers->hasCacheControlDirective('must-revalidate'));\n        $this->assertFalse($response->headers->has(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER));\n    }\n\n    public function testPrivateResponseMaxAgeIsRespectedIfSessionStarted()\n    {\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $session = $this->createMock(Session::class);\n        $session->expects($this->once())->method('getUsageIndex')->willReturn(1);\n        $request = new Request([], [], [], [], [], ['SERVER_PROTOCOL' => 'HTTP/1.0']);\n        $request->setSession($session);\n\n        $response = new Response();\n        $response->headers->set('Cache-Control', 'no-cache');\n        $response->prepare($request);\n\n        $listener = new SessionListener(new Container());\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));\n\n        $this->assertSame(0, $response->getMaxAge());\n        $this->assertFalse($response->headers->hasCacheControlDirective('public'));\n        $this->assertTrue($response->headers->hasCacheControlDirective('private'));\n        $this->assertTrue($response->headers->hasCacheControlDirective('must-revalidate'));\n        $this->assertLessThanOrEqual(new \\DateTimeImmutable('now', new \\DateTimeZone('UTC')), new \\DateTimeImmutable($response->headers->get('Expires')));\n        $this->assertFalse($response->headers->has(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER));\n    }\n\n    public function testSurrogateMainRequestIsPublic()\n    {\n        $session = $this->createMock(Session::class);\n        $session->expects($this->exactly(1))->method('getName')->willReturn('PHPSESSID');\n        $session->expects($this->exactly(2))->method('getUsageIndex')->willReturn(0, 1);\n        $sessionFactory = $this->createMock(SessionFactory::class);\n        $sessionFactory->expects($this->once())->method('createSession')->willReturn($session);\n\n        $container = new Container();\n        $container->set('session_factory', $sessionFactory);\n\n        $listener = new SessionListener($container);\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $request = new Request();\n        $response = new Response();\n        $response->setCache(['public' => true, 'max_age' => '30']);\n        $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));\n        $this->assertTrue($request->hasSession());\n\n        $subRequest = clone $request;\n        $this->assertSame($request->getSession(), $subRequest->getSession());\n        $listener->onKernelRequest(new RequestEvent($kernel, $subRequest, HttpKernelInterface::MAIN_REQUEST));\n        $listener->onKernelResponse(new ResponseEvent($kernel, $subRequest, HttpKernelInterface::MAIN_REQUEST, $response));\n\n        $this->assertFalse($response->headers->has('Expires'));\n        $this->assertFalse($response->headers->hasCacheControlDirective('private'));\n        $this->assertFalse($response->headers->hasCacheControlDirective('must-revalidate'));\n        $this->assertSame('30', $response->headers->getCacheControlDirective('max-age'));\n\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));\n\n        $this->assertTrue($response->headers->hasCacheControlDirective('private'));\n        $this->assertTrue($response->headers->hasCacheControlDirective('must-revalidate'));\n        $this->assertSame('0', $response->headers->getCacheControlDirective('max-age'));\n\n        $this->assertTrue($response->headers->has('Expires'));\n        $this->assertLessThanOrEqual(new \\DateTimeImmutable('now', new \\DateTimeZone('UTC')), new \\DateTimeImmutable($response->headers->get('Expires')));\n    }\n\n    public function testGetSessionIsCalledOnce()\n    {\n        $session = $this->createMock(Session::class);\n        $session->expects($this->exactly(1))->method('getName')->willReturn('PHPSESSID');\n        $sessionFactory = $this->createMock(SessionFactory::class);\n        $sessionFactory->expects($this->once())->method('createSession')->willReturn($session);\n        $kernel = $this->createStub(KernelInterface::class);\n\n        $requestStack = new RequestStack();\n        $requestStack->push($mainRequest = new Request([], [], [], [], [], ['HTTPS' => 'on']));\n\n        $container = new Container();\n        $container->set('session_factory', $sessionFactory);\n        $container->set('request_stack', $requestStack);\n\n        $event = new RequestEvent($kernel, $mainRequest, HttpKernelInterface::MAIN_REQUEST);\n\n        $listener = new SessionListener($container);\n        $listener->onKernelRequest($event);\n\n        // storage->setOptions() should have been called already\n        $subRequest = $mainRequest->duplicate();\n        // at this point both main and subrequest have a closure to build the session\n\n        $mainRequest->getSession();\n\n        // calling the factory on the subRequest should not trigger a second call to storage->setOptions()\n        $subRequest->getSession();\n    }\n\n    public function testGetSessionSetsSessionOnMainRequest()\n    {\n        $mainRequest = new Request();\n        $listener = $this->createListener($mainRequest, new NativeSessionStorageFactory());\n\n        $event = new RequestEvent($this->createStub(HttpKernelInterface::class), $mainRequest, HttpKernelInterface::MAIN_REQUEST);\n        $listener->onKernelRequest($event);\n\n        $this->assertFalse($mainRequest->hasSession(true));\n\n        $subRequest = $mainRequest->duplicate();\n\n        $event = new RequestEvent($this->createStub(HttpKernelInterface::class), $subRequest, HttpKernelInterface::SUB_REQUEST);\n        $listener->onKernelRequest($event);\n\n        $session = $subRequest->getSession();\n\n        $this->assertTrue($mainRequest->hasSession(true));\n        $this->assertSame($session, $mainRequest->getSession());\n    }\n\n    public function testSessionUsageExceptionIfStatelessAndSessionUsed()\n    {\n        $session = $this->createMock(Session::class);\n        $session->expects($this->once())->method('getUsageIndex')->willReturn(1);\n        $session->expects($this->once())->method('getName')->willReturn('foo');\n        $sessionFactory = $this->createMock(SessionFactory::class);\n        $sessionFactory->expects($this->once())->method('createSession')->willReturn($session);\n\n        $container = new Container();\n        $container->set('session_factory', $sessionFactory);\n\n        $listener = new SessionListener($container, true);\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $request = new Request();\n        $request->attributes->set('_stateless', true);\n        $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));\n        $request->getSession();\n\n        $this->expectException(UnexpectedSessionUsageException::class);\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, new Response()));\n    }\n\n    public function testSessionUsageLogIfStatelessAndSessionUsed()\n    {\n        $session = $this->createMock(Session::class);\n        $session->expects($this->once())->method('getName')->willReturn('foo');\n        $session->expects($this->once())->method('getUsageIndex')->willReturn(1);\n        $sessionFactory = $this->createMock(SessionFactory::class);\n        $sessionFactory->expects($this->once())->method('createSession')->willReturn($session);\n\n        $logger = $this->createMock(LoggerInterface::class);\n        $logger->expects($this->exactly(1))->method('warning');\n\n        $container = new Container();\n        $container->set('session_factory', $sessionFactory);\n        $container->set('logger', $logger);\n\n        $listener = new SessionListener($container, false);\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $request = new Request();\n        $request->attributes->set('_stateless', true);\n        $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));\n        $request->getSession();\n\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, new Response()));\n    }\n\n    public function testSessionIsSavedWhenUnexpectedSessionExceptionThrown()\n    {\n        $session = $this->createMock(Session::class);\n        $session->expects($this->exactly(1))->method('getId')->willReturn('123456');\n        $session->expects($this->exactly(1))->method('getName')->willReturn('PHPSESSID');\n        $session->method('isStarted')->willReturn(true);\n        $session->expects($this->once())->method('getUsageIndex')->willReturn(1);\n        $session->expects($this->exactly(1))->method('save');\n        $sessionFactory = $this->createMock(SessionFactory::class);\n        $sessionFactory->expects($this->once())->method('createSession')->willReturn($session);\n\n        $container = new Container();\n        $container->set('session_factory', $sessionFactory);\n\n        $listener = new SessionListener($container, true);\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $request = new Request();\n        $request->attributes->set('_stateless', true);\n\n        $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));\n        $request->getSession();\n\n        $response = new Response();\n        $this->expectException(UnexpectedSessionUsageException::class);\n        $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));\n    }\n\n    public function testSessionUsageCallbackWhenDebugAndStateless()\n    {\n        $session = $this->createMock(Session::class);\n        $session->method('isStarted')->willReturn(true);\n        $session->expects($this->exactly(1))->method('save');\n\n        $requestStack = new RequestStack();\n\n        $request = new Request();\n        $request->attributes->set('_stateless', true);\n\n        $requestStack->push(new Request());\n        $requestStack->push($request);\n        $requestStack->push($subRequest = new Request());\n        $subRequest->setSession($session);\n\n        $collector = $this->createMock(RequestDataCollector::class);\n        $collector->expects($this->once())->method('collectSessionUsage');\n\n        $container = new Container();\n        $container->set('request_stack', $requestStack);\n        $container->set('session_collector', $collector->collectSessionUsage(...));\n\n        $this->expectException(UnexpectedSessionUsageException::class);\n        (new SessionListener($container, true))->onSessionUsage();\n    }\n\n    public function testSessionUsageCallbackWhenNoDebug()\n    {\n        $session = $this->createMock(Session::class);\n        $session->method('isStarted')->willReturn(true);\n        $session->expects($this->exactly(0))->method('save');\n\n        $request = new Request();\n        $request->attributes->set('_stateless', true);\n\n        $requestStack = new RequestStack();\n        $requestStack->push($request);\n\n        $collector = $this->createMock(RequestDataCollector::class);\n        $collector->expects($this->never())->method('collectSessionUsage');\n\n        $container = new Container();\n        $container->set('request_stack', $requestStack);\n        $container->set('session_collector', $collector);\n\n        (new SessionListener($container))->onSessionUsage();\n    }\n\n    public function testSessionUsageCallbackWhenNoStateless()\n    {\n        $session = $this->createMock(Session::class);\n        $session->method('isStarted')->willReturn(true);\n        $session->expects($this->never())->method('save');\n\n        $requestStack = new RequestStack();\n        $requestStack->push(new Request());\n        $requestStack->push(new Request());\n\n        $container = new Container();\n        $container->set('request_stack', $requestStack);\n\n        (new SessionListener($container, true))->onSessionUsage();\n    }\n\n    #[RunInSeparateProcess]\n    public function testReset()\n    {\n        session_start();\n        $_SESSION['test'] = ['test'];\n        session_write_close();\n\n        $this->assertNotEmpty($_SESSION);\n        $this->assertNotEmpty(session_id());\n\n        $container = new Container();\n\n        (new SessionListener($container, true))->reset();\n\n        $this->assertSame([], $_SESSION);\n        $this->assertSame('', session_id());\n        $this->assertSame(\\PHP_SESSION_NONE, session_status());\n    }\n\n    #[RunInSeparateProcess]\n    public function testResetUnclosedSession()\n    {\n        session_start();\n        $_SESSION['test'] = ['test'];\n\n        $this->assertNotEmpty($_SESSION);\n        $this->assertNotEmpty(session_id());\n        $this->assertSame(\\PHP_SESSION_ACTIVE, session_status());\n\n        $container = new Container();\n\n        (new SessionListener($container, true))->reset();\n\n        $this->assertSame([], $_SESSION);\n        $this->assertSame('', session_id());\n        $this->assertSame(\\PHP_SESSION_NONE, session_status());\n    }\n\n    private function createListener(Request $request, SessionStorageFactoryInterface $sessionFactory)\n    {\n        $requestStack = new RequestStack();\n        $request = new Request();\n        $requestStack->push($request);\n\n        $sessionFactory = new SessionFactory($requestStack, $sessionFactory);\n\n        $container = new Container();\n        $container->set('request_stack', $requestStack);\n        $container->set('session_factory', $sessionFactory);\n\n        $listener = new SessionListener($container);\n\n        return new SessionListener($container);\n    }\n\n    private function createValidSessionId(): string\n    {\n        session_start();\n        $sessionId = session_id();\n        $_SESSION['some'] = 'value';\n        session_write_close();\n        $_SESSION = [];\n        session_abort();\n\n        return $sessionId;\n    }\n}\n"
  },
  {
    "path": "Tests/EventListener/SurrogateListenerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\EventListener;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\EventDispatcher\\EventDispatcher;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Event\\ResponseEvent;\nuse Symfony\\Component\\HttpKernel\\EventListener\\SurrogateListener;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\Esi;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\n\nclass SurrogateListenerTest extends TestCase\n{\n    public function testFilterDoesNothingForSubRequests()\n    {\n        $dispatcher = new EventDispatcher();\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $response = new Response('foo <esi:include src=\"\" />');\n        $listener = new SurrogateListener(new Esi());\n\n        $dispatcher->addListener(KernelEvents::RESPONSE, $listener->onKernelResponse(...));\n        $event = new ResponseEvent($kernel, new Request(), HttpKernelInterface::SUB_REQUEST, $response);\n        $dispatcher->dispatch($event, KernelEvents::RESPONSE);\n\n        $this->assertEquals('', $event->getResponse()->headers->get('Surrogate-Control'));\n    }\n\n    public function testFilterWhenThereIsSomeEsiIncludes()\n    {\n        $dispatcher = new EventDispatcher();\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $response = new Response('foo <esi:include src=\"\" />');\n        $listener = new SurrogateListener(new Esi());\n\n        $dispatcher->addListener(KernelEvents::RESPONSE, $listener->onKernelResponse(...));\n        $event = new ResponseEvent($kernel, new Request(), HttpKernelInterface::MAIN_REQUEST, $response);\n        $dispatcher->dispatch($event, KernelEvents::RESPONSE);\n\n        $this->assertEquals('content=\"ESI/1.0\"', $event->getResponse()->headers->get('Surrogate-Control'));\n    }\n\n    public function testFilterWhenThereIsNoEsiIncludes()\n    {\n        $dispatcher = new EventDispatcher();\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $response = new Response('foo');\n        $listener = new SurrogateListener(new Esi());\n\n        $dispatcher->addListener(KernelEvents::RESPONSE, $listener->onKernelResponse(...));\n        $event = new ResponseEvent($kernel, new Request(), HttpKernelInterface::MAIN_REQUEST, $response);\n        $dispatcher->dispatch($event, KernelEvents::RESPONSE);\n\n        $this->assertEquals('', $event->getResponse()->headers->get('Surrogate-Control'));\n    }\n}\n"
  },
  {
    "path": "Tests/EventListener/ValidateRequestListenerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\EventListener;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\EventDispatcher\\EventDispatcher;\nuse Symfony\\Component\\HttpFoundation\\Exception\\ConflictingHeadersException;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Event\\RequestEvent;\nuse Symfony\\Component\\HttpKernel\\EventListener\\ValidateRequestListener;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\n\nclass ValidateRequestListenerTest extends TestCase\n{\n    protected function tearDown(): void\n    {\n        Request::setTrustedProxies([], -1);\n    }\n\n    public function testListenerThrowsWhenMainRequestHasInconsistentClientIps()\n    {\n        $this->expectException(ConflictingHeadersException::class);\n        $dispatcher = new EventDispatcher();\n        $kernel = $this->createStub(HttpKernelInterface::class);\n\n        $request = new Request();\n        $request->setTrustedProxies(['1.1.1.1'], Request::HEADER_X_FORWARDED_FOR | Request::HEADER_FORWARDED);\n        $request->server->set('REMOTE_ADDR', '1.1.1.1');\n        $request->headers->set('FORWARDED', 'for=2.2.2.2');\n        $request->headers->set('X_FORWARDED_FOR', '3.3.3.3');\n\n        $dispatcher->addListener(KernelEvents::REQUEST, [new ValidateRequestListener(), 'onKernelRequest']);\n        $event = new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST);\n\n        $dispatcher->dispatch($event, KernelEvents::REQUEST);\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/AccessDeniedHttpExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Exception;\n\nuse Symfony\\Component\\HttpKernel\\Exception\\AccessDeniedHttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\n\nclass AccessDeniedHttpExceptionTest extends HttpExceptionTest\n{\n    protected function createException(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = []): HttpException\n    {\n        return new AccessDeniedHttpException($message, $previous, $code, $headers);\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/BadRequestHttpExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Exception;\n\nuse Symfony\\Component\\HttpKernel\\Exception\\BadRequestHttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\n\nclass BadRequestHttpExceptionTest extends HttpExceptionTest\n{\n    protected function createException(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = []): HttpException\n    {\n        return new BadRequestHttpException($message, $previous, $code, $headers);\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/ConflictHttpExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Exception;\n\nuse Symfony\\Component\\HttpKernel\\Exception\\ConflictHttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\n\nclass ConflictHttpExceptionTest extends HttpExceptionTest\n{\n    protected function createException(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = []): HttpException\n    {\n        return new ConflictHttpException($message, $previous, $code, $headers);\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/GoneHttpExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Exception;\n\nuse Symfony\\Component\\HttpKernel\\Exception\\GoneHttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\n\nclass GoneHttpExceptionTest extends HttpExceptionTest\n{\n    protected function createException(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = []): HttpException\n    {\n        return new GoneHttpException($message, $previous, $code, $headers);\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/HttpExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Exception;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\n\nclass HttpExceptionTest extends TestCase\n{\n    public static function headerDataProvider()\n    {\n        return [\n            [['X-Test' => 'Test']],\n            [['X-Test' => 1]],\n            [\n                [\n                    ['X-Test' => 'Test'],\n                    ['X-Test-2' => 'Test-2'],\n                ],\n            ],\n        ];\n    }\n\n    public function testHeadersDefault()\n    {\n        $exception = $this->createException();\n        $this->assertSame([], $exception->getHeaders());\n    }\n\n    #[DataProvider('headerDataProvider')]\n    public function testHeadersConstructor($headers)\n    {\n        $exception = new HttpException(200, '', null, $headers);\n        $this->assertSame($headers, $exception->getHeaders());\n    }\n\n    #[DataProvider('headerDataProvider')]\n    public function testHeadersSetter($headers)\n    {\n        $exception = $this->createException();\n        $exception->setHeaders($headers);\n        $this->assertSame($headers, $exception->getHeaders());\n    }\n\n    public function testThrowableIsAllowedForPrevious()\n    {\n        $previous = new class('Error of PHP 7+') extends \\Error {\n        };\n        $exception = $this->createException('', $previous);\n        $this->assertSame($previous, $exception->getPrevious());\n    }\n\n    #[DataProvider('provideStatusCode')]\n    public function testFromStatusCode(int $statusCode)\n    {\n        $exception = HttpException::fromStatusCode($statusCode);\n        $this->assertInstanceOf(HttpException::class, $exception);\n        $this->assertSame($statusCode, $exception->getStatusCode());\n    }\n\n    public static function provideStatusCode()\n    {\n        return [\n            [400],\n            [401],\n            [403],\n            [404],\n            [406],\n            [409],\n            [410],\n            [411],\n            [412],\n            [418],\n            [423],\n            [415],\n            [422],\n            [428],\n            [429],\n            [503],\n        ];\n    }\n\n    protected function createException(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = []): HttpException\n    {\n        return new HttpException(200, $message, $previous, $headers, $code);\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/LengthRequiredHttpExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Exception;\n\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\LengthRequiredHttpException;\n\nclass LengthRequiredHttpExceptionTest extends HttpExceptionTest\n{\n    protected function createException(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = []): HttpException\n    {\n        return new LengthRequiredHttpException($message, $previous, $code, $headers);\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/LockedHttpExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Exception;\n\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\LockedHttpException;\n\nclass LockedHttpExceptionTest extends HttpExceptionTest\n{\n    protected function createException(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = []): HttpException\n    {\n        return new LockedHttpException($message, $previous, $code, $headers);\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/MethodNotAllowedHttpExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Exception;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\MethodNotAllowedHttpException;\n\nclass MethodNotAllowedHttpExceptionTest extends HttpExceptionTest\n{\n    public function testHeadersDefault()\n    {\n        $exception = new MethodNotAllowedHttpException(['GET', 'PUT']);\n        $this->assertSame(['Allow' => 'GET, PUT'], $exception->getHeaders());\n    }\n\n    public function testWithHeaderConstruct()\n    {\n        $headers = [\n            'Cache-Control' => 'public, s-maxage=1200',\n        ];\n\n        $exception = new MethodNotAllowedHttpException(['get'], '', null, 0, $headers);\n\n        $headers['Allow'] = 'GET';\n\n        $this->assertSame($headers, $exception->getHeaders());\n    }\n\n    #[DataProvider('headerDataProvider')]\n    public function testHeadersSetter($headers)\n    {\n        $exception = new MethodNotAllowedHttpException(['GET']);\n        $exception->setHeaders($headers);\n        $this->assertSame($headers, $exception->getHeaders());\n    }\n\n    protected function createException(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = []): HttpException\n    {\n        return new MethodNotAllowedHttpException(['get'], $message, $previous, $code, $headers);\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/NotAcceptableHttpExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Exception;\n\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\NotAcceptableHttpException;\n\nclass NotAcceptableHttpExceptionTest extends HttpExceptionTest\n{\n    protected function createException(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = []): HttpException\n    {\n        return new NotAcceptableHttpException($message, $previous, $code, $headers);\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/NotFoundHttpExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Exception;\n\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;\n\nclass NotFoundHttpExceptionTest extends HttpExceptionTest\n{\n    protected function createException(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = []): HttpException\n    {\n        return new NotFoundHttpException($message, $previous, $code, $headers);\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/PreconditionFailedHttpExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Exception;\n\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\PreconditionFailedHttpException;\n\nclass PreconditionFailedHttpExceptionTest extends HttpExceptionTest\n{\n    protected function createException(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = []): HttpException\n    {\n        return new PreconditionFailedHttpException($message, $previous, $code, $headers);\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/PreconditionRequiredHttpExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Exception;\n\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\PreconditionRequiredHttpException;\n\nclass PreconditionRequiredHttpExceptionTest extends HttpExceptionTest\n{\n    protected function createException(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = []): HttpException\n    {\n        return new PreconditionRequiredHttpException($message, $previous, $code, $headers);\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/ServiceUnavailableHttpExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Exception;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\ServiceUnavailableHttpException;\n\nclass ServiceUnavailableHttpExceptionTest extends HttpExceptionTest\n{\n    public function testHeadersDefaultRetryAfter()\n    {\n        $exception = new ServiceUnavailableHttpException(10);\n        $this->assertSame(['Retry-After' => 10], $exception->getHeaders());\n    }\n\n    public function testWithHeaderConstruct()\n    {\n        $headers = [\n            'Cache-Control' => 'public, s-maxage=1337',\n        ];\n\n        $exception = new ServiceUnavailableHttpException(1337, '', null, 0, $headers);\n\n        $headers['Retry-After'] = 1337;\n\n        $this->assertSame($headers, $exception->getHeaders());\n    }\n\n    #[DataProvider('headerDataProvider')]\n    public function testHeadersSetter($headers)\n    {\n        $exception = new ServiceUnavailableHttpException(10);\n        $exception->setHeaders($headers);\n        $this->assertSame($headers, $exception->getHeaders());\n    }\n\n    protected function createException(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = []): HttpException\n    {\n        return new ServiceUnavailableHttpException(null, $message, $previous, $code, $headers);\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/TooManyRequestsHttpExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Exception;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\TooManyRequestsHttpException;\n\nclass TooManyRequestsHttpExceptionTest extends HttpExceptionTest\n{\n    public function testHeadersDefaultRertyAfter()\n    {\n        $exception = new TooManyRequestsHttpException(10);\n        $this->assertSame(['Retry-After' => 10], $exception->getHeaders());\n    }\n\n    public function testWithHeaderConstruct()\n    {\n        $headers = [\n            'Cache-Control' => 'public, s-maxage=69',\n        ];\n\n        $exception = new TooManyRequestsHttpException(69, '', null, 0, $headers);\n\n        $headers['Retry-After'] = 69;\n\n        $this->assertSame($headers, $exception->getHeaders());\n    }\n\n    #[DataProvider('headerDataProvider')]\n    public function testHeadersSetter($headers)\n    {\n        $exception = new TooManyRequestsHttpException(10);\n        $exception->setHeaders($headers);\n        $this->assertSame($headers, $exception->getHeaders());\n    }\n\n    protected function createException(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = []): HttpException\n    {\n        return new TooManyRequestsHttpException(null, $message, $previous, $code, $headers);\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/UnauthorizedHttpExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Exception;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\UnauthorizedHttpException;\n\nclass UnauthorizedHttpExceptionTest extends HttpExceptionTest\n{\n    public function testHeadersDefault()\n    {\n        $exception = new UnauthorizedHttpException('Challenge');\n        $this->assertSame(['WWW-Authenticate' => 'Challenge'], $exception->getHeaders());\n    }\n\n    public function testWithHeaderConstruct()\n    {\n        $headers = [\n            'Cache-Control' => 'public, s-maxage=1200',\n        ];\n\n        $exception = new UnauthorizedHttpException('Challenge', '', null, 0, $headers);\n\n        $headers['WWW-Authenticate'] = 'Challenge';\n\n        $this->assertSame($headers, $exception->getHeaders());\n    }\n\n    #[DataProvider('headerDataProvider')]\n    public function testHeadersSetter($headers)\n    {\n        $exception = new UnauthorizedHttpException('Challenge');\n        $exception->setHeaders($headers);\n        $this->assertSame($headers, $exception->getHeaders());\n    }\n\n    protected function createException(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = []): HttpException\n    {\n        return new UnauthorizedHttpException('Challenge', $message, $previous, $code, $headers);\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/UnprocessableEntityHttpExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Exception;\n\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\UnprocessableEntityHttpException;\n\nclass UnprocessableEntityHttpExceptionTest extends HttpExceptionTest\n{\n    protected function createException(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = []): HttpException\n    {\n        return new UnprocessableEntityHttpException($message, $previous, $code, $headers);\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/UnsupportedMediaTypeHttpExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Exception;\n\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\UnsupportedMediaTypeHttpException;\n\nclass UnsupportedMediaTypeHttpExceptionTest extends HttpExceptionTest\n{\n    protected function createException(string $message = '', ?\\Throwable $previous = null, int $code = 0, array $headers = []): HttpException\n    {\n        return new UnsupportedMediaTypeHttpException($message, $previous, $code, $headers);\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/AcmeFooBundle/AcmeFooBundle.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\AcmeFooBundle;\n\nuse Symfony\\Component\\Config\\Definition\\Configurator\\DefinitionConfigurator;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ContainerConfigurator;\nuse Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle;\n\nclass AcmeFooBundle extends AbstractBundle\n{\n    public function configure(DefinitionConfigurator $definition): void\n    {\n        $definition->rootNode()\n            ->children()\n                ->scalarNode('foo')->defaultValue('bar')->end()\n            ->end()\n        ;\n\n        $definition->import('Resources/config/definition.php');\n    }\n\n    public function prependExtension(ContainerConfigurator $container, ContainerBuilder $builder): void\n    {\n        $builder->prependExtensionConfig('loaded', ['bar' => 'baz']);\n    }\n\n    public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void\n    {\n        $container->parameters()\n            ->set('acme_foo.config', $config)\n        ;\n\n        $container->services()\n            ->set('acme_foo.foo', \\stdClass::class)\n        ;\n\n        $container->import('Resources/config/services.php');\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/AcmeFooBundle/Resources/config/definition.php",
    "content": "<?php\n\nuse Symfony\\Component\\Config\\Definition\\Configurator\\DefinitionConfigurator;\n\nreturn static function (DefinitionConfigurator $definition) {\n    $definition->rootNode()\n        ->children()\n            ->scalarNode('ping')->defaultValue('pong')->end()\n        ->end()\n    ;\n};\n"
  },
  {
    "path": "Tests/Fixtures/AcmeFooBundle/Resources/config/services.php",
    "content": "<?php\n\nuse Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ContainerConfigurator;\n\nreturn static function (ContainerConfigurator $container) {\n    $container->services()\n        ->set('acme_foo.bar', \\stdClass::class)\n    ;\n};\n"
  },
  {
    "path": "Tests/Fixtures/Attribute/Bar.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute;\n\n#[\\Attribute(\\Attribute::TARGET_CLASS | \\Attribute::TARGET_METHOD | \\Attribute::TARGET_FUNCTION | \\Attribute::IS_REPEATABLE)]\nclass Bar\n{\n    public function __construct(\n        public mixed $foo,\n    ) {\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/Attribute/Baz.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute;\n\n#[\\Attribute(\\Attribute::TARGET_CLASS | \\Attribute::TARGET_METHOD | \\Attribute::TARGET_FUNCTION | \\Attribute::IS_REPEATABLE)]\nclass Baz\n{\n}\n"
  },
  {
    "path": "Tests/Fixtures/Attribute/Buz.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute;\n\n#[\\Attribute(\\Attribute::TARGET_CLASS | \\Attribute::TARGET_METHOD)]\nclass Buz\n{\n}\n"
  },
  {
    "path": "Tests/Fixtures/Attribute/Foo.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute;\n\n#[\\Attribute(\\Attribute::TARGET_PARAMETER)]\nclass Foo\n{\n    private $foo;\n\n    public function __construct($foo)\n    {\n        $this->foo = $foo;\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/Attribute/Qux.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute;\n\n#[\\Attribute(\\Attribute::TARGET_CLASS | \\Attribute::TARGET_METHOD)]\nclass Qux\n{\n}\n"
  },
  {
    "path": "Tests/Fixtures/Attribute/SubBuz.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute;\n\n#[\\Attribute(\\Attribute::TARGET_CLASS | \\Attribute::TARGET_METHOD)]\nclass SubBuz extends Buz\n{\n}\n"
  },
  {
    "path": "Tests/Fixtures/Bundle1Bundle/Resources/.gitkeep",
    "content": ""
  },
  {
    "path": "Tests/Fixtures/Bundle1Bundle/foo.txt",
    "content": ""
  },
  {
    "path": "Tests/Fixtures/BundleCompilerPass/BundleAsCompilerPassBundle.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\BundleCompilerPass;\n\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle;\n\nclass BundleAsCompilerPassBundle extends AbstractBundle implements CompilerPassInterface\n{\n    public function process(ContainerBuilder $container): void\n    {\n        $container->register('foo', \\stdClass::class)\n            ->setPublic(true);\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/ClearableService.php",
    "content": "<?php\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures;\n\nclass ClearableService\n{\n    public static $counter = 0;\n\n    public function clear()\n    {\n        ++self::$counter;\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/Controller/ArgumentResolver/UploadedFile/file-big.txt",
    "content": "I'm not big, but I'm big enough to carry more than 50 bytes inside me.\n"
  },
  {
    "path": "Tests/Fixtures/Controller/ArgumentResolver/UploadedFile/file-small.txt",
    "content": "I'm a file with less than 50 bytes.\n"
  },
  {
    "path": "Tests/Fixtures/Controller/AttributeController.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller;\n\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute\\Bar;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute\\Baz;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute\\Foo;\n\n#[Bar('class'), Undefined('class')]\nclass AttributeController\n{\n    #[Bar('method'), Baz, Undefined('method')]\n    public function __invoke()\n    {\n    }\n\n    public function action(#[Foo('bar')] string $baz)\n    {\n    }\n\n    public function multiAttributeArg(#[Foo('bar'), Undefined('bar')] string $baz)\n    {\n    }\n\n    public function issue41478(#[Foo('bar')] string $baz, string $bat)\n    {\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/Controller/BasicTypesController.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller;\n\nclass BasicTypesController\n{\n    public function action(string $foo, int $bar, float $baz)\n    {\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/Controller/CacheAttributeController.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller;\n\nuse Symfony\\Component\\HttpKernel\\Attribute\\Cache;\n\n#[Cache(smaxage: 20)]\nclass CacheAttributeController\n{\n    public const CLASS_SMAXAGE = 20;\n    public const METHOD_SMAXAGE = 25;\n\n    #[Cache(smaxage: 25)]\n    public function foo()\n    {\n    }\n\n    public function bar()\n    {\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/Controller/ControllerAttributesController.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller;\n\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute\\Buz;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute\\Qux;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute\\SubBuz;\n\n#[Buz]\nclass ControllerAttributesController\n{\n    #[Buz]\n    #[Qux]\n    public function buzQuxAction()\n    {\n    }\n\n    #[Buz]\n    public function buzAction()\n    {\n    }\n\n    #[SubBuz]\n    public function subBuzAction()\n    {\n    }\n\n    public function noAttributeAction()\n    {\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/Controller/ExtendingRequest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\n\nclass ExtendingRequest extends Request\n{\n}\n"
  },
  {
    "path": "Tests/Fixtures/Controller/ExtendingSession.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller;\n\nuse Symfony\\Component\\HttpFoundation\\Session\\Session;\n\nclass ExtendingSession extends Session\n{\n}\n"
  },
  {
    "path": "Tests/Fixtures/Controller/NullableController.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller;\n\nclass NullableController\n{\n    public function action(?string $foo, ?\\stdClass $bar, ?string $baz = 'value', string $last = '')\n    {\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/Controller/VariadicController.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Controller;\n\nclass VariadicController\n{\n    public function action($foo, ...$bar)\n    {\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/DataCollector/CloneVarDataCollector.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\DataCollector;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\DataCollector;\nuse Symfony\\Component\\VarDumper\\Cloner\\Data;\n\nfinal class CloneVarDataCollector extends DataCollector\n{\n    private $varToClone;\n\n    public function __construct($varToClone)\n    {\n        $this->varToClone = $varToClone;\n    }\n\n    public function collect(Request $request, Response $response, ?\\Throwable $exception = null): void\n    {\n        $this->data = $this->cloneVar($this->varToClone);\n    }\n\n    public function getData(): Data\n    {\n        return $this->data;\n    }\n\n    public function getName(): string\n    {\n        return 'clone_var';\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/DataCollector/DummyController.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\DataCollector;\n\nclass DummyController\n{\n    /**\n     * Dummy method used as controller callable.\n     */\n    public static function staticControllerMethod()\n    {\n        throw new \\LogicException('Unexpected method call');\n    }\n\n    /**\n     * Magic method to allow non existing methods to be called and delegated.\n     */\n    public function __call(string $method, array $args)\n    {\n        throw new \\LogicException('Unexpected method call');\n    }\n\n    /**\n     * Magic method to allow non existing methods to be called and delegated.\n     */\n    public static function __callStatic(string $method, array $args)\n    {\n        throw new \\LogicException('Unexpected method call');\n    }\n\n    public function __invoke()\n    {\n        throw new \\LogicException('Unexpected method call');\n    }\n\n    public function regularCallable()\n    {\n        throw new \\LogicException('Unexpected method call');\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/ExtensionNotValidBundle/DependencyInjection/ExtensionNotValidExtension.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\ExtensionNotValidBundle\\DependencyInjection;\n\nclass ExtensionNotValidExtension\n{\n    public function getAlias()\n    {\n        return 'extension_not_valid';\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/ExtensionNotValidBundle/ExtensionNotValidBundle.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\ExtensionNotValidBundle;\n\nuse Symfony\\Component\\HttpKernel\\Bundle\\Bundle;\n\nclass ExtensionNotValidBundle extends Bundle\n{\n}\n"
  },
  {
    "path": "Tests/Fixtures/ExtensionPresentBundle/DependencyInjection/ExtensionPresentExtension.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\ExtensionPresentBundle\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Extension\\Extension;\n\nclass ExtensionPresentExtension extends Extension\n{\n    public function load(array $configs, ContainerBuilder $container): void\n    {\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/ExtensionPresentBundle/ExtensionPresentBundle.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\ExtensionPresentBundle;\n\nuse Symfony\\Component\\HttpKernel\\Bundle\\Bundle;\n\nclass ExtensionPresentBundle extends Bundle\n{\n}\n"
  },
  {
    "path": "Tests/Fixtures/IntEnum.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures;\n\nenum IntEnum: int\n{\n    case One = 1;\n    case Two = 2;\n}\n"
  },
  {
    "path": "Tests/Fixtures/IsSignatureValidAttributeController.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures;\n\nuse Symfony\\Component\\HttpKernel\\Attribute\\IsSignatureValid;\n\n#[IsSignatureValid]\nclass IsSignatureValidAttributeController\n{\n    public function __invoke()\n    {\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/IsSignatureValidAttributeMethodsController.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures;\n\nuse Symfony\\Component\\HttpKernel\\Attribute\\IsSignatureValid;\n\nclass IsSignatureValidAttributeMethodsController\n{\n    public function noAttribute()\n    {\n    }\n\n    #[IsSignatureValid]\n    public function withDefaultBehavior()\n    {\n    }\n\n    #[IsSignatureValid]\n    #[IsSignatureValid]\n    public function withMultiple()\n    {\n    }\n\n    #[IsSignatureValid(methods: 'POST')]\n    public function withPostOnly()\n    {\n    }\n\n    #[IsSignatureValid(methods: ['GET', 'POST'])]\n    public function withGetAndPost()\n    {\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/KernelWithoutBundles.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures;\n\nuse Symfony\\Component\\Config\\Loader\\LoaderInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\HttpKernel\\Kernel;\n\nclass KernelWithoutBundles extends Kernel\n{\n    public function registerBundles(): iterable\n    {\n        return [];\n    }\n\n    public function registerContainerConfiguration(LoaderInterface $loader): void\n    {\n    }\n\n    public function getProjectDir(): string\n    {\n        return __DIR__;\n    }\n\n    protected function build(ContainerBuilder $container): void\n    {\n        $container->setParameter('test_executed', true);\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/LazyResettableService.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures;\n\nclass LazyResettableService extends \\stdClass\n{\n    public static $counter = 0;\n\n    public function foo(): bool\n    {\n        return true;\n    }\n\n    public function reset(): void\n    {\n        ++self::$counter;\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/MockableUploadFileWithClientSize.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures;\n\nuse Symfony\\Component\\HttpFoundation\\File\\UploadedFile;\n\nclass MockableUploadFileWithClientSize extends UploadedFile\n{\n    public function getClientSize(): int\n    {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/MultiResettableService.php",
    "content": "<?php\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures;\n\nclass MultiResettableService\n{\n    public static $resetFirstCounter = 0;\n    public static $resetSecondCounter = 0;\n\n    public function resetFirst()\n    {\n        ++self::$resetFirstCounter;\n    }\n\n    public function resetSecond()\n    {\n        ++self::$resetSecondCounter;\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/ResettableService.php",
    "content": "<?php\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures;\n\nclass ResettableService\n{\n    public static $counter = 0;\n\n    public function reset()\n    {\n        ++self::$counter;\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/Suit.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures;\n\nenum Suit: string\n{\n    case Hearts = 'H';\n    case Diamonds = 'D';\n    case Clubs = 'C';\n    case Spades = 'S';\n}\n"
  },
  {
    "path": "Tests/Fixtures/TestClient.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures;\n\nuse Symfony\\Component\\HttpKernel\\HttpKernelBrowser;\n\nclass TestClient extends HttpKernelBrowser\n{\n    protected function getScript($request): string\n    {\n        $script = parent::getScript($request);\n\n        $autoload = file_exists(__DIR__.'/../../vendor/autoload.php')\n            ? __DIR__.'/../../vendor/autoload.php'\n            : __DIR__.'/../../../../../../vendor/autoload.php'\n        ;\n\n        $script = preg_replace('/(\\->register\\(\\);)/', \"$0\\nrequire_once '$autoload';\\n\", $script);\n\n        return $script;\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/UsePropertyInDestruct.php",
    "content": "<?php\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures;\n\nclass UsePropertyInDestruct\n{\n    public string $name;\n    public $parent = null;\n\n    public function __destruct()\n    {\n        if ($this->parent !== null) {\n            $this->parent->name = '';\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/WithPublicObjectProperty.php",
    "content": "<?php\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fixtures;\n\nclass WithPublicObjectProperty\n{\n    public ?WithPublicObjectProperty $parent = null;\n}\n"
  },
  {
    "path": "Tests/Fragment/EsiFragmentRendererTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fragment;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\UriSigner;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerReference;\nuse Symfony\\Component\\HttpKernel\\Fragment\\EsiFragmentRenderer;\nuse Symfony\\Component\\HttpKernel\\Fragment\\InlineFragmentRenderer;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\Esi;\n\nclass EsiFragmentRendererTest extends TestCase\n{\n    public function testRenderFallbackToInlineStrategyIfEsiNotSupported()\n    {\n        $strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy(true));\n        $strategy->render('/', Request::create('/'));\n    }\n\n    public function testRenderFallbackWithScalar()\n    {\n        $strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy(true), new UriSigner('foo'));\n        $request = Request::create('/');\n        $reference = new ControllerReference('main_controller', ['foo' => [true]], []);\n        $strategy->render($reference, $request);\n    }\n\n    public function testRender()\n    {\n        $strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy());\n\n        $request = Request::create('/');\n        $request->setLocale('fr');\n        $request->headers->set('Surrogate-Capability', 'ESI/1.0');\n\n        $this->assertEquals('<esi:include src=\"/\" />', $strategy->render('/', $request)->getContent());\n        $this->assertEquals(\"<esi:comment text=\\\"This is a comment\\\" />\\n<esi:include src=\\\"/\\\" />\", $strategy->render('/', $request, ['comment' => 'This is a comment'])->getContent());\n        $this->assertEquals('<esi:include src=\"/\" alt=\"foo\" />', $strategy->render('/', $request, ['alt' => 'foo'])->getContent());\n    }\n\n    public function testRenderControllerReference()\n    {\n        $signer = new UriSigner('foo');\n        $strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy(), $signer);\n\n        $request = Request::create('/');\n        $request->setLocale('fr');\n        $request->headers->set('Surrogate-Capability', 'ESI/1.0');\n\n        $reference = new ControllerReference('main_controller', [], []);\n        $altReference = new ControllerReference('alt_controller', [], []);\n\n        $this->assertMatchesRegularExpression(\n            '#^<esi:include src=\"/_fragment\\?_hash=.+&_path=_format%3Dhtml%26_locale%3Dfr%26_controller%3Dmain_controller\" alt=\"/_fragment\\?_hash=.+&_path=_format%3Dhtml%26_locale%3Dfr%26_controller%3Dalt_controller\" />$#',\n            $strategy->render($reference, $request, ['alt' => $altReference])->getContent()\n        );\n    }\n\n    public function testRenderControllerReferenceWithAbsoluteUri()\n    {\n        $signer = new UriSigner('foo');\n        $strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy(), $signer);\n\n        $request = Request::create('http://localhost/');\n        $request->setLocale('fr');\n        $request->headers->set('Surrogate-Capability', 'ESI/1.0');\n\n        $reference = new ControllerReference('main_controller', [], []);\n        $altReference = new ControllerReference('alt_controller', [], []);\n\n        $this->assertMatchesRegularExpression(\n            '#^<esi:include src=\"http://localhost/_fragment\\?_hash=.+&_path=_format%3Dhtml%26_locale%3Dfr%26_controller%3Dmain_controller\" alt=\"http://localhost/_fragment\\?_hash=.+&_path=_format%3Dhtml%26_locale%3Dfr%26_controller%3Dalt_controller\" />$#',\n            $strategy->render($reference, $request, ['alt' => $altReference, 'absolute_uri' => true])->getContent()\n        );\n    }\n\n    public function testRenderControllerReferenceWithoutSignerThrowsException()\n    {\n        $this->expectException(\\LogicException::class);\n        $strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy());\n\n        $request = Request::create('/');\n        $request->setLocale('fr');\n        $request->headers->set('Surrogate-Capability', 'ESI/1.0');\n\n        $strategy->render(new ControllerReference('main_controller'), $request);\n    }\n\n    public function testRenderAltControllerReferenceWithoutSignerThrowsException()\n    {\n        $this->expectException(\\LogicException::class);\n        $strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy());\n\n        $request = Request::create('/');\n        $request->setLocale('fr');\n        $request->headers->set('Surrogate-Capability', 'ESI/1.0');\n\n        $strategy->render('/', $request, ['alt' => new ControllerReference('alt_controller')]);\n    }\n\n    private function getInlineStrategy($called = false)\n    {\n        if (!$called) {\n            return $this->createStub(InlineFragmentRenderer::class);\n        }\n\n        $inline = $this->createMock(InlineFragmentRenderer::class);\n        $inline->expects($this->once())->method('render');\n\n        return $inline;\n    }\n}\n"
  },
  {
    "path": "Tests/Fragment/FragmentHandlerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fragment;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\nuse Symfony\\Component\\HttpKernel\\Fragment\\FragmentHandler;\nuse Symfony\\Component\\HttpKernel\\Fragment\\FragmentRendererInterface;\n\nclass FragmentHandlerTest extends TestCase\n{\n    private RequestStack $requestStack;\n\n    protected function setUp(): void\n    {\n        $this->requestStack = new RequestStack();\n        $this->requestStack->push(Request::create('/'));\n    }\n\n    public function testRenderWhenRendererDoesNotExist()\n    {\n        $this->expectException(\\InvalidArgumentException::class);\n        $handler = new FragmentHandler($this->requestStack);\n        $handler->render('/', 'foo');\n    }\n\n    public function testRenderWithUnknownRenderer()\n    {\n        $this->expectException(\\InvalidArgumentException::class);\n        $handler = $this->getHandler(new Response('foo'));\n\n        $handler->render('/', 'bar');\n    }\n\n    public function testDeliverWithUnsuccessfulResponse()\n    {\n        $handler = $this->getHandler(new Response('foo', 404));\n        try {\n            $handler->render('/', 'foo');\n            $this->fail('->render() throws a \\RuntimeException exception if response is not successful');\n        } catch (\\Exception $e) {\n            $this->assertInstanceOf(\\RuntimeException::class, $e);\n            $this->assertEquals(0, $e->getCode());\n            $this->assertEquals('Error when rendering \"http://localhost/\" (Status code is 404).', $e->getMessage());\n\n            $previousException = $e->getPrevious();\n            $this->assertInstanceOf(HttpException::class, $previousException);\n            $this->assertEquals(404, $previousException->getStatusCode());\n            $this->assertEquals(0, $previousException->getCode());\n        }\n    }\n\n    public function testRender()\n    {\n        $expectedRequest = Request::create('/');\n        $handler = $this->getHandler(\n            new Response('foo'),\n            [\n                '/',\n                $this->callback(static function (Request $request) use ($expectedRequest) {\n                    $expectedRequest->server->remove('REQUEST_TIME_FLOAT');\n                    $request->server->remove('REQUEST_TIME_FLOAT');\n\n                    return $expectedRequest == $request;\n                }),\n                ['foo' => 'foo', 'ignore_errors' => true],\n            ]\n        );\n\n        $this->assertEquals('foo', $handler->render('/', 'foo', ['foo' => 'foo']));\n    }\n\n    protected function getHandler($returnValue, $arguments = [])\n    {\n        if ($arguments) {\n            $renderer = $this->createMock(FragmentRendererInterface::class);\n            $renderer->method('getName')->willReturn('foo');\n            $renderer\n                ->expects($this->once())\n                ->method('render')\n                ->with(...$arguments)\n                ->willReturn($returnValue);\n        } else {\n            $renderer = $this->createStub(FragmentRendererInterface::class);\n            $renderer->method('getName')->willReturn('foo');\n            $renderer\n                ->method('render')\n                ->willReturn($returnValue);\n        }\n\n        $handler = new FragmentHandler($this->requestStack);\n        $handler->addRenderer($renderer);\n\n        return $handler;\n    }\n}\n"
  },
  {
    "path": "Tests/Fragment/HIncludeFragmentRendererTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fragment;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\UriSigner;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerReference;\nuse Symfony\\Component\\HttpKernel\\Fragment\\HIncludeFragmentRenderer;\nuse Twig\\Environment;\nuse Twig\\Loader\\ArrayLoader;\n\nclass HIncludeFragmentRendererTest extends TestCase\n{\n    public function testRenderExceptionWhenControllerAndNoSigner()\n    {\n        $this->expectException(\\LogicException::class);\n        $strategy = new HIncludeFragmentRenderer();\n        $strategy->render(new ControllerReference('main_controller', [], []), Request::create('/'));\n    }\n\n    public function testRenderWithControllerAndSigner()\n    {\n        $strategy = new HIncludeFragmentRenderer(null, new UriSigner('foo'));\n\n        $this->assertMatchesRegularExpression('#^<hx:include src=\"/_fragment\\?_hash=.+&amp;_path=_format%3Dhtml%26_locale%3Den%26_controller%3Dmain_controller\"></hx:include>$#', $strategy->render(new ControllerReference('main_controller', [], []), Request::create('/'))->getContent());\n    }\n\n    public function testRenderWithUri()\n    {\n        $strategy = new HIncludeFragmentRenderer();\n        $this->assertEquals('<hx:include src=\"/foo\"></hx:include>', $strategy->render('/foo', Request::create('/'))->getContent());\n\n        $strategy = new HIncludeFragmentRenderer(null, new UriSigner('foo'));\n        $this->assertEquals('<hx:include src=\"/foo\"></hx:include>', $strategy->render('/foo', Request::create('/'))->getContent());\n    }\n\n    public function testRenderWithDefault()\n    {\n        // only default\n        $strategy = new HIncludeFragmentRenderer();\n        $this->assertEquals('<hx:include src=\"/foo\">default</hx:include>', $strategy->render('/foo', Request::create('/'), ['default' => 'default'])->getContent());\n\n        // only global default\n        $strategy = new HIncludeFragmentRenderer(null, null, 'global_default');\n        $this->assertEquals('<hx:include src=\"/foo\">global_default</hx:include>', $strategy->render('/foo', Request::create('/'), [])->getContent());\n\n        // global default and default\n        $strategy = new HIncludeFragmentRenderer(null, null, 'global_default');\n        $this->assertEquals('<hx:include src=\"/foo\">default</hx:include>', $strategy->render('/foo', Request::create('/'), ['default' => 'default'])->getContent());\n    }\n\n    public function testRenderWithAttributesOptions()\n    {\n        // with id\n        $strategy = new HIncludeFragmentRenderer();\n        $this->assertEquals('<hx:include src=\"/foo\" id=\"bar\">default</hx:include>', $strategy->render('/foo', Request::create('/'), ['default' => 'default', 'id' => 'bar'])->getContent());\n\n        // with attributes\n        $strategy = new HIncludeFragmentRenderer();\n        $this->assertEquals('<hx:include src=\"/foo\" p1=\"v1\" p2=\"v2\">default</hx:include>', $strategy->render('/foo', Request::create('/'), ['default' => 'default', 'attributes' => ['p1' => 'v1', 'p2' => 'v2']])->getContent());\n\n        // with id & attributes\n        $strategy = new HIncludeFragmentRenderer();\n        $this->assertEquals('<hx:include src=\"/foo\" p1=\"v1\" p2=\"v2\" id=\"bar\">default</hx:include>', $strategy->render('/foo', Request::create('/'), ['default' => 'default', 'id' => 'bar', 'attributes' => ['p1' => 'v1', 'p2' => 'v2']])->getContent());\n    }\n\n    public function testRenderWithTwigAndDefaultText()\n    {\n        $twig = new Environment($loader = new ArrayLoader());\n        $strategy = new HIncludeFragmentRenderer($twig);\n        $this->assertEquals('<hx:include src=\"/foo\">loading...</hx:include>', $strategy->render('/foo', Request::create('/'), ['default' => 'loading...'])->getContent());\n    }\n}\n"
  },
  {
    "path": "Tests/Fragment/InlineFragmentRendererTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fragment;\n\nuse PHPUnit\\Framework\\Attributes\\Group;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\EventDispatcher\\EventDispatcher;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolverInterface;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerReference;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface;\nuse Symfony\\Component\\HttpKernel\\Event\\ExceptionEvent;\nuse Symfony\\Component\\HttpKernel\\Fragment\\InlineFragmentRenderer;\nuse Symfony\\Component\\HttpKernel\\HttpKernel;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\nuse Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface;\n\n#[Group('time-sensitive')]\nclass InlineFragmentRendererTest extends TestCase\n{\n    public function testRender()\n    {\n        $strategy = new InlineFragmentRenderer($this->getKernel(new Response('foo')));\n\n        $this->assertEquals('foo', $strategy->render('/', Request::create('/'))->getContent());\n    }\n\n    public function testRenderWithControllerReference()\n    {\n        $strategy = new InlineFragmentRenderer($this->getKernel(new Response('foo')));\n\n        $this->assertEquals('foo', $strategy->render(new ControllerReference('main_controller', [], []), Request::create('/'))->getContent());\n    }\n\n    public function testRenderWithObjectsAsAttributes()\n    {\n        $object = new \\stdClass();\n\n        $subRequest = Request::create('/_fragment?_path=_format%3Dhtml%26_locale%3Den%26_controller%3Dmain_controller');\n        $subRequest->attributes->replace(['object' => $object, '_format' => 'html', '_controller' => 'main_controller', '_locale' => 'en']);\n        $subRequest->headers->set('x-forwarded-for', ['127.0.0.1']);\n        $subRequest->headers->set('forwarded', ['for=\"127.0.0.1\";host=\"localhost\";proto=http']);\n        $subRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');\n        $subRequest->server->set('HTTP_FORWARDED', 'for=\"127.0.0.1\";host=\"localhost\";proto=http');\n\n        $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($subRequest));\n\n        $this->assertSame('foo', $strategy->render(new ControllerReference('main_controller', ['object' => $object], []), Request::create('/'))->getContent());\n    }\n\n    public function testRenderWithTrustedHeaderDisabled()\n    {\n        Request::setTrustedProxies([], 0);\n\n        $expectedSubRequest = Request::create('/');\n        $expectedSubRequest->headers->set('x-forwarded-for', ['127.0.0.1']);\n        $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');\n\n        $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));\n        $this->assertSame('foo', $strategy->render('/', Request::create('/'))->getContent());\n\n        Request::setTrustedProxies([], -1);\n    }\n\n    public function testRenderExceptionNoIgnoreErrors()\n    {\n        $this->expectException(\\RuntimeException::class);\n        $dispatcher = $this->createMock(EventDispatcherInterface::class);\n        $dispatcher->expects($this->never())->method('dispatch');\n\n        $strategy = new InlineFragmentRenderer($this->getKernel(new \\RuntimeException('foo')), $dispatcher);\n\n        $this->assertEquals('foo', $strategy->render('/', Request::create('/'))->getContent());\n    }\n\n    public function testRenderExceptionIgnoreErrors()\n    {\n        $exception = new \\RuntimeException('foo');\n        $kernel = $this->getKernel($exception);\n        $request = Request::create('/');\n        $expectedEvent = new ExceptionEvent($kernel, $request, $kernel::SUB_REQUEST, $exception);\n        $dispatcher = $this->createMock(EventDispatcherInterface::class);\n        $dispatcher->expects($this->once())->method('dispatch')->with($expectedEvent, KernelEvents::EXCEPTION);\n\n        $strategy = new InlineFragmentRenderer($kernel, $dispatcher);\n\n        $this->assertSame('', $strategy->render('/', $request, ['ignore_errors' => true])->getContent());\n    }\n\n    public function testRenderExceptionIgnoreErrorsWithAlt()\n    {\n        $strategy = new InlineFragmentRenderer($this->getKernel(static function () {\n            static $firstCall = true;\n\n            if ($firstCall) {\n                $firstCall = false;\n\n                throw new \\RuntimeException('foo');\n            }\n\n            return new Response('bar');\n        }));\n\n        $this->assertEquals('bar', $strategy->render('/', Request::create('/'), ['ignore_errors' => true, 'alt' => '/foo'])->getContent());\n    }\n\n    private function getKernel($returnValue)\n    {\n        $kernel = $this->createStub(HttpKernelInterface::class);\n        $mocker = $kernel\n            ->method('handle')\n        ;\n\n        if ($returnValue instanceof \\Exception) {\n            $mocker->willThrowException($returnValue);\n        } elseif ($returnValue instanceof \\Closure) {\n            $mocker->willReturnCallback($returnValue);\n        } else {\n            $mocker->willReturn(...(\\is_array($returnValue) ? $returnValue : [$returnValue]));\n        }\n\n        return $kernel;\n    }\n\n    public function testExceptionInSubRequestsDoesNotMangleOutputBuffers()\n    {\n        $controllerResolver = $this->createMock(ControllerResolverInterface::class);\n        $controllerResolver\n            ->expects($this->once())\n            ->method('getController')\n            ->willReturn(static function () {\n                ob_start();\n                echo 'bar';\n                throw new \\RuntimeException();\n            })\n        ;\n\n        $argumentResolver = $this->createMock(ArgumentResolverInterface::class);\n        $argumentResolver\n            ->expects($this->once())\n            ->method('getArguments')\n            ->willReturn([])\n        ;\n\n        $kernel = new HttpKernel(new EventDispatcher(), $controllerResolver, new RequestStack(), $argumentResolver);\n        $renderer = new InlineFragmentRenderer($kernel);\n\n        // simulate a main request with output buffering\n        ob_start();\n        echo 'Foo';\n\n        // simulate a sub-request with output buffering and an exception\n        $renderer->render('/', Request::create('/'), ['ignore_errors' => true]);\n\n        $this->assertEquals('Foo', ob_get_clean());\n    }\n\n    public function testLocaleAndFormatAreKeptInSubrequest()\n    {\n        $expectedSubRequest = Request::create('/');\n        $expectedSubRequest->attributes->set('_format', 'foo');\n        $expectedSubRequest->setLocale('fr');\n        if (Request::HEADER_X_FORWARDED_FOR & Request::getTrustedHeaderSet()) {\n            $expectedSubRequest->headers->set('x-forwarded-for', ['127.0.0.1']);\n            $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');\n        }\n        $expectedSubRequest->headers->set('forwarded', ['for=\"127.0.0.1\";host=\"localhost\";proto=http']);\n        $expectedSubRequest->server->set('HTTP_FORWARDED', 'for=\"127.0.0.1\";host=\"localhost\";proto=http');\n\n        $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));\n\n        $request = Request::create('/');\n        $request->attributes->set('_format', 'foo');\n        $request->setLocale('fr');\n        $strategy->render('/', $request);\n    }\n\n    public function testESIHeaderIsKeptInSubrequest()\n    {\n        $expectedSubRequest = Request::create('/');\n        $expectedSubRequest->headers->set('Surrogate-Capability', 'abc=\"ESI/1.0\"');\n\n        if (Request::HEADER_X_FORWARDED_FOR & Request::getTrustedHeaderSet()) {\n            $expectedSubRequest->headers->set('x-forwarded-for', ['127.0.0.1']);\n            $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');\n        }\n        $expectedSubRequest->headers->set('forwarded', ['for=\"127.0.0.1\";host=\"localhost\";proto=http']);\n        $expectedSubRequest->server->set('HTTP_FORWARDED', 'for=\"127.0.0.1\";host=\"localhost\";proto=http');\n\n        $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));\n\n        $request = Request::create('/');\n        $request->headers->set('Surrogate-Capability', 'abc=\"ESI/1.0\"');\n        $strategy->render('/', $request);\n    }\n\n    public function testESIHeaderIsKeptInSubrequestWithTrustedHeaderDisabled()\n    {\n        Request::setTrustedProxies([], Request::HEADER_FORWARDED);\n\n        $this->testESIHeaderIsKeptInSubrequest();\n\n        Request::setTrustedProxies([], -1);\n    }\n\n    public function testHeadersPossiblyResultingIn304AreNotAssignedToSubrequest()\n    {\n        $expectedSubRequest = Request::create('/');\n        $expectedSubRequest->headers->set('x-forwarded-for', ['127.0.0.1']);\n        $expectedSubRequest->headers->set('forwarded', ['for=\"127.0.0.1\";host=\"localhost\";proto=http']);\n        $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');\n        $expectedSubRequest->server->set('HTTP_FORWARDED', 'for=\"127.0.0.1\";host=\"localhost\";proto=http');\n\n        $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));\n        $request = Request::create('/', 'GET', [], [], [], ['HTTP_IF_MODIFIED_SINCE' => 'Fri, 01 Jan 2016 00:00:00 GMT', 'HTTP_IF_NONE_MATCH' => '*']);\n        $strategy->render('/', $request);\n    }\n\n    public function testFirstTrustedProxyIsSetAsRemote()\n    {\n        Request::setTrustedProxies(['1.1.1.1'], -1);\n\n        $expectedSubRequest = Request::create('/');\n        $expectedSubRequest->headers->set('Surrogate-Capability', 'abc=\"ESI/1.0\"');\n        $expectedSubRequest->server->set('REMOTE_ADDR', '127.0.0.1');\n        $expectedSubRequest->headers->set('x-forwarded-for', ['127.0.0.1']);\n        $expectedSubRequest->headers->set('forwarded', ['for=\"127.0.0.1\";host=\"localhost\";proto=http']);\n        $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');\n        $expectedSubRequest->server->set('HTTP_FORWARDED', 'for=\"127.0.0.1\";host=\"localhost\";proto=http');\n\n        $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));\n\n        $request = Request::create('/');\n        $request->headers->set('Surrogate-Capability', 'abc=\"ESI/1.0\"');\n        $strategy->render('/', $request);\n\n        Request::setTrustedProxies([], -1);\n    }\n\n    public function testIpAddressOfRangedTrustedProxyIsSetAsRemote()\n    {\n        $expectedSubRequest = Request::create('/');\n        $expectedSubRequest->headers->set('Surrogate-Capability', 'abc=\"ESI/1.0\"');\n        $expectedSubRequest->server->set('REMOTE_ADDR', '127.0.0.1');\n        $expectedSubRequest->headers->set('x-forwarded-for', ['127.0.0.1']);\n        $expectedSubRequest->headers->set('forwarded', ['for=\"127.0.0.1\";host=\"localhost\";proto=http']);\n        $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');\n        $expectedSubRequest->server->set('HTTP_FORWARDED', 'for=\"127.0.0.1\";host=\"localhost\";proto=http');\n\n        Request::setTrustedProxies(['1.1.1.1/24'], -1);\n\n        $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));\n\n        $request = Request::create('/');\n        $request->headers->set('Surrogate-Capability', 'abc=\"ESI/1.0\"');\n        $strategy->render('/', $request);\n\n        Request::setTrustedProxies([], -1);\n    }\n\n    public function testStatelessAttributeIsForwardedByDefault()\n    {\n        $request = Request::create('/');\n        $request->attributes->set('_stateless', true);\n\n        $kernel = $this->createMock(HttpKernelInterface::class);\n        $kernel\n            ->expects($this->once())\n            ->method('handle')\n            ->with($this->callback(static fn (Request $subRequest) => $subRequest->attributes->get('_stateless')))\n        ;\n        $strategy = new InlineFragmentRenderer($kernel);\n        $strategy->render('/', $request);\n    }\n\n    public function testStatelessAttributeCanBeDisabled()\n    {\n        $request = Request::create('/');\n        $request->attributes->set('_stateless', true);\n\n        $kernel = $this->createMock(HttpKernelInterface::class);\n        $kernel\n            ->expects($this->once())\n            ->method('handle')\n            ->with($this->callback(static fn (Request $subRequest) => !$subRequest->attributes->get('_stateless')))\n        ;\n        $strategy = new InlineFragmentRenderer($kernel);\n        $strategy->render(new ControllerReference('main_controller', ['_stateless' => false]), $request);\n    }\n\n    /**\n     * Creates a Kernel expecting a request equals to $request.\n     */\n    private function getKernelExpectingRequest(Request $expectedRequest)\n    {\n        $kernel = $this->createMock(HttpKernelInterface::class);\n        $kernel\n            ->expects($this->once())\n            ->method('handle')\n            ->with($this->callback(static function (Request $request) use ($expectedRequest) {\n                $expectedRequest->server->remove('REQUEST_TIME_FLOAT');\n                $request->server->remove('REQUEST_TIME_FLOAT');\n\n                return $expectedRequest == $request;\n            }))\n            ->willReturn(new Response('foo'));\n\n        return $kernel;\n    }\n}\n\nclass Bar\n{\n    public string $bar = 'bar';\n\n    public function getBar()\n    {\n        return $this->bar;\n    }\n}\n"
  },
  {
    "path": "Tests/Fragment/RoutableFragmentRendererTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fragment;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerReference;\nuse Symfony\\Component\\HttpKernel\\Fragment\\RoutableFragmentRenderer;\n\nclass RoutableFragmentRendererTest extends TestCase\n{\n    #[DataProvider('getGenerateFragmentUriData')]\n    public function testGenerateFragmentUri($uri, $controller)\n    {\n        $this->assertEquals($uri, $this->callGenerateFragmentUriMethod($controller, Request::create('/')));\n    }\n\n    #[DataProvider('getGenerateFragmentUriData')]\n    public function testGenerateAbsoluteFragmentUri($uri, $controller)\n    {\n        $this->assertEquals('http://localhost'.$uri, $this->callGenerateFragmentUriMethod($controller, Request::create('/'), true));\n    }\n\n    public static function getGenerateFragmentUriData()\n    {\n        return [\n            ['/_fragment?_path=_format%3Dhtml%26_locale%3Den%26_controller%3Dcontroller', new ControllerReference('controller', [], [])],\n            ['/_fragment?_path=_format%3Dxml%26_locale%3Den%26_controller%3Dcontroller', new ControllerReference('controller', ['_format' => 'xml'], [])],\n            ['/_fragment?_path=foo%3Dfoo%26_format%3Djson%26_locale%3Den%26_controller%3Dcontroller', new ControllerReference('controller', ['foo' => 'foo', '_format' => 'json'], [])],\n            ['/_fragment?bar=bar&_path=foo%3Dfoo%26_format%3Dhtml%26_locale%3Den%26_controller%3Dcontroller', new ControllerReference('controller', ['foo' => 'foo'], ['bar' => 'bar'])],\n            ['/_fragment?foo=foo&_path=_format%3Dhtml%26_locale%3Den%26_controller%3Dcontroller', new ControllerReference('controller', [], ['foo' => 'foo'])],\n            ['/_fragment?_path=foo%255B0%255D%3Dfoo%26foo%255B1%255D%3Dbar%26_format%3Dhtml%26_locale%3Den%26_controller%3Dcontroller', new ControllerReference('controller', ['foo' => ['foo', 'bar']], [])],\n        ];\n    }\n\n    public function testGenerateFragmentUriWithARequest()\n    {\n        $request = Request::create('/');\n        $request->attributes->set('_format', 'json');\n        $request->setLocale('fr');\n        $controller = new ControllerReference('controller', [], []);\n\n        $this->assertEquals('/_fragment?_path=_format%3Djson%26_locale%3Dfr%26_controller%3Dcontroller', $this->callGenerateFragmentUriMethod($controller, $request));\n    }\n\n    #[DataProvider('getGenerateFragmentUriDataWithNonScalar')]\n    public function testGenerateFragmentUriWithNonScalar($controller)\n    {\n        $this->expectException(\\LogicException::class);\n        $this->callGenerateFragmentUriMethod($controller, Request::create('/'));\n    }\n\n    public static function getGenerateFragmentUriDataWithNonScalar()\n    {\n        return [\n            [new ControllerReference('controller', ['foo' => new Foo(), 'bar' => 'bar'], [])],\n            [new ControllerReference('controller', ['foo' => ['foo' => 'foo'], 'bar' => ['bar' => new Foo()]], [])],\n        ];\n    }\n\n    private function callGenerateFragmentUriMethod(ControllerReference $reference, Request $request, $absolute = false)\n    {\n        $renderer = $this->createStub(RoutableFragmentRenderer::class);\n        $r = new \\ReflectionObject($renderer);\n        $m = $r->getMethod('generateFragmentUri');\n\n        return $m->invoke($renderer, $reference, $request, $absolute);\n    }\n}\n\nclass Foo\n{\n    public $foo;\n\n    public function getFoo()\n    {\n        return $this->foo;\n    }\n}\n"
  },
  {
    "path": "Tests/Fragment/SsiFragmentRendererTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Fragment;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\UriSigner;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerReference;\nuse Symfony\\Component\\HttpKernel\\Fragment\\InlineFragmentRenderer;\nuse Symfony\\Component\\HttpKernel\\Fragment\\SsiFragmentRenderer;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\Ssi;\n\nclass SsiFragmentRendererTest extends TestCase\n{\n    public function testRenderFallbackToInlineStrategyIfSsiNotSupported()\n    {\n        $strategy = new SsiFragmentRenderer(new Ssi(), $this->getInlineStrategy(true));\n        $strategy->render('/', Request::create('/'));\n    }\n\n    public function testRender()\n    {\n        $strategy = new SsiFragmentRenderer(new Ssi(), $this->getInlineStrategy());\n\n        $request = Request::create('/');\n        $request->setLocale('fr');\n        $request->headers->set('Surrogate-Capability', 'SSI/1.0');\n\n        $this->assertEquals('<!--#include virtual=\"/\" -->', $strategy->render('/', $request)->getContent());\n        $this->assertEquals('<!--#include virtual=\"/\" -->', $strategy->render('/', $request, ['comment' => 'This is a comment'])->getContent(), 'Strategy options should not impact the ssi include tag');\n    }\n\n    public function testRenderControllerReference()\n    {\n        $signer = new UriSigner('foo');\n        $strategy = new SsiFragmentRenderer(new Ssi(), $this->getInlineStrategy(), $signer);\n\n        $request = Request::create('/');\n        $request->setLocale('fr');\n        $request->headers->set('Surrogate-Capability', 'SSI/1.0');\n\n        $reference = new ControllerReference('main_controller', [], []);\n        $altReference = new ControllerReference('alt_controller', [], []);\n\n        $this->assertMatchesRegularExpression(\n            '{^<!--#include virtual=\"/_fragment\\?_hash=.+&_path=_format%3Dhtml%26_locale%3Dfr%26_controller%3Dmain_controller\" -->$}',\n            $strategy->render($reference, $request, ['alt' => $altReference])->getContent()\n        );\n    }\n\n    public function testRenderControllerReferenceWithAbsoluteUri()\n    {\n        $signer = new UriSigner('foo');\n        $strategy = new SsiFragmentRenderer(new Ssi(), $this->getInlineStrategy(), $signer);\n\n        $request = Request::create('http://localhost/');\n        $request->setLocale('fr');\n        $request->headers->set('Surrogate-Capability', 'SSI/1.0');\n\n        $reference = new ControllerReference('main_controller', [], []);\n        $altReference = new ControllerReference('alt_controller', [], []);\n\n        $this->assertMatchesRegularExpression(\n            '{^<!--#include virtual=\"http://localhost/_fragment\\?_hash=.+&_path=_format%3Dhtml%26_locale%3Dfr%26_controller%3Dmain_controller\" -->$}',\n            $strategy->render($reference, $request, ['alt' => $altReference, 'absolute_uri' => true])->getContent()\n        );\n    }\n\n    public function testRenderControllerReferenceWithoutSignerThrowsException()\n    {\n        $this->expectException(\\LogicException::class);\n        $strategy = new SsiFragmentRenderer(new Ssi(), $this->getInlineStrategy());\n\n        $request = Request::create('/');\n        $request->setLocale('fr');\n        $request->headers->set('Surrogate-Capability', 'SSI/1.0');\n\n        $strategy->render(new ControllerReference('main_controller'), $request);\n    }\n\n    public function testRenderAltControllerReferenceWithoutSignerThrowsException()\n    {\n        $this->expectException(\\LogicException::class);\n        $strategy = new SsiFragmentRenderer(new Ssi(), $this->getInlineStrategy());\n\n        $request = Request::create('/');\n        $request->setLocale('fr');\n        $request->headers->set('Surrogate-Capability', 'SSI/1.0');\n\n        $strategy->render('/', $request, ['alt' => new ControllerReference('alt_controller')]);\n    }\n\n    private function getInlineStrategy($called = false)\n    {\n        if (!$called) {\n            return $this->createStub(InlineFragmentRenderer::class);\n        }\n\n        $inline = $this->createMock(InlineFragmentRenderer::class);\n        $inline->expects($this->once())->method('render');\n\n        return $inline;\n    }\n}\n"
  },
  {
    "path": "Tests/HttpCache/EsiTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\HttpCache;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\Esi;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache;\n\nclass EsiTest extends TestCase\n{\n    public function testHasSurrogateEsiCapability()\n    {\n        $esi = new Esi();\n\n        $request = Request::create('/');\n        $request->headers->set('Surrogate-Capability', 'abc=\"ESI/1.0\"');\n        $this->assertTrue($esi->hasSurrogateCapability($request));\n\n        $request = Request::create('/');\n        $request->headers->set('Surrogate-Capability', 'foobar');\n        $this->assertFalse($esi->hasSurrogateCapability($request));\n\n        $request = Request::create('/');\n        $this->assertFalse($esi->hasSurrogateCapability($request));\n    }\n\n    public function testAddSurrogateEsiCapability()\n    {\n        $esi = new Esi();\n\n        $request = Request::create('/');\n        $esi->addSurrogateCapability($request);\n        $this->assertEquals('symfony=\"ESI/1.0\"', $request->headers->get('Surrogate-Capability'));\n\n        $esi->addSurrogateCapability($request);\n        $this->assertEquals('symfony=\"ESI/1.0\", symfony=\"ESI/1.0\"', $request->headers->get('Surrogate-Capability'));\n    }\n\n    public function testAddSurrogateControl()\n    {\n        $esi = new Esi();\n\n        $response = new Response('foo <esi:include src=\"\" />');\n        $esi->addSurrogateControl($response);\n        $this->assertEquals('content=\"ESI/1.0\"', $response->headers->get('Surrogate-Control'));\n\n        $response = new Response('foo');\n        $esi->addSurrogateControl($response);\n        $this->assertEquals('', $response->headers->get('Surrogate-Control'));\n    }\n\n    public function testNeedsEsiParsing()\n    {\n        $esi = new Esi();\n\n        $response = new Response();\n        $response->headers->set('Surrogate-Control', 'content=\"ESI/1.0\"');\n        $this->assertTrue($esi->needsParsing($response));\n\n        $response = new Response();\n        $this->assertFalse($esi->needsParsing($response));\n    }\n\n    public function testRenderIncludeTag()\n    {\n        $esi = new Esi();\n\n        $this->assertEquals('<esi:include src=\"/\" onerror=\"continue\" alt=\"/alt\" />', $esi->renderIncludeTag('/', '/alt', true));\n        $this->assertEquals('<esi:include src=\"/\" alt=\"/alt\" />', $esi->renderIncludeTag('/', '/alt', false));\n        $this->assertEquals('<esi:include src=\"/\" onerror=\"continue\" />', $esi->renderIncludeTag('/'));\n        $this->assertEquals('<esi:comment text=\"some comment\" />'.\"\\n\".'<esi:include src=\"/\" onerror=\"continue\" alt=\"/alt\" />', $esi->renderIncludeTag('/', '/alt', true, 'some comment'));\n    }\n\n    public function testProcessDoesNothingIfContentTypeIsNotHtml()\n    {\n        $esi = new Esi();\n\n        $request = Request::create('/');\n        $response = new Response();\n        $response->headers->set('Content-Type', 'text/plain');\n        $this->assertSame($response, $esi->process($request, $response));\n\n        $this->assertFalse($response->headers->has('x-body-eval'));\n    }\n\n    public function testMultilineEsiRemoveTagsAreRemoved()\n    {\n        $esi = new Esi();\n\n        $request = Request::create('/');\n        $response = new Response('<esi:remove> <a href=\"http://www.example.com\">www.example.com</a> </esi:remove> Keep this'.\"<esi:remove>\\n <a>www.example.com</a> </esi:remove> And this\");\n        $this->assertSame($response, $esi->process($request, $response));\n\n        $this->assertEquals(' Keep this And this', substr($response->getContent(), 24, -24));\n    }\n\n    public function testCommentTagsAreRemoved()\n    {\n        $esi = new Esi();\n\n        $request = Request::create('/');\n        $response = new Response('<esi:comment text=\"some comment &gt;\" /> Keep this');\n        $this->assertSame($response, $esi->process($request, $response));\n\n        $this->assertEquals(' Keep this', substr($response->getContent(), 24, -24));\n    }\n\n    public function testProcess()\n    {\n        $esi = new Esi();\n\n        $request = Request::create('/');\n        $response = new Response('foo <esi:comment text=\"some comment\" /><esi:include src=\"...\" alt=\"alt\" onerror=\"continue\" />');\n        $this->assertSame($response, $esi->process($request, $response));\n\n        $content = explode(substr($response->getContent(), 0, 24), $response->getContent());\n        $this->assertSame(['', 'foo ', \"...\\nalt\\n1\\n\", ''], $content);\n        $this->assertEquals('ESI', $response->headers->get('x-body-eval'));\n\n        $response = new Response('foo <esi:comment text=\"some comment\" /><esi:include src=\"foo\\'\" alt=\"bar\\'\" onerror=\"continue\" />');\n        $this->assertSame($response, $esi->process($request, $response));\n\n        $content = explode(substr($response->getContent(), 0, 24), $response->getContent());\n        $this->assertSame(['', 'foo ', \"foo'\\nbar'\\n1\\n\", ''], $content);\n\n        $response = new Response('foo <esi:include src=\"...\" />');\n        $this->assertSame($response, $esi->process($request, $response));\n\n        $content = explode(substr($response->getContent(), 0, 24), $response->getContent());\n        $this->assertSame(['', 'foo ', \"...\\n\\n\\n\", ''], $content);\n\n        $response = new Response('foo <esi:include src=\"...\"></esi:include>');\n        $this->assertSame($response, $esi->process($request, $response));\n\n        $content = explode(substr($response->getContent(), 0, 24), $response->getContent());\n        $this->assertSame(['', 'foo ', \"...\\n\\n\\n\", ''], $content);\n    }\n\n    public function testProcessEscapesPhpTags()\n    {\n        $esi = new Esi();\n\n        $request = Request::create('/');\n        $response = new Response('<?php <? <% <script language=php>');\n        $this->assertSame($response, $esi->process($request, $response));\n\n        $content = explode(substr($response->getContent(), 0, 24), $response->getContent());\n        $this->assertSame(['', '<?php <? <% <script language=php>', ''], $content);\n    }\n\n    public function testProcessWhenNoSrcInAnEsi()\n    {\n        $this->expectException(\\RuntimeException::class);\n        $esi = new Esi();\n\n        $request = Request::create('/');\n        $response = new Response('foo <esi:include />');\n        $this->assertSame($response, $esi->process($request, $response));\n    }\n\n    public function testProcessRemoveSurrogateControlHeader()\n    {\n        $esi = new Esi();\n\n        $request = Request::create('/');\n        $response = new Response('foo <esi:include src=\"...\" />');\n        $response->headers->set('Surrogate-Control', 'content=\"ESI/1.0\"');\n        $this->assertSame($response, $esi->process($request, $response));\n        $this->assertEquals('ESI', $response->headers->get('x-body-eval'));\n\n        $response->headers->set('Surrogate-Control', 'no-store, content=\"ESI/1.0\"');\n        $this->assertSame($response, $esi->process($request, $response));\n        $this->assertEquals('ESI', $response->headers->get('x-body-eval'));\n        $this->assertEquals('no-store', $response->headers->get('surrogate-control'));\n\n        $response->headers->set('Surrogate-Control', 'content=\"ESI/1.0\", no-store');\n        $this->assertSame($response, $esi->process($request, $response));\n        $this->assertEquals('ESI', $response->headers->get('x-body-eval'));\n        $this->assertEquals('no-store', $response->headers->get('surrogate-control'));\n    }\n\n    public function testHandle()\n    {\n        $esi = new Esi();\n        $cache = $this->getCache(Request::create('/'), new Response('foo'));\n        $this->assertEquals('foo', $esi->handle($cache, '/', '/alt', true));\n    }\n\n    public function testHandleWhenResponseIsNot200()\n    {\n        $this->expectException(\\RuntimeException::class);\n        $esi = new Esi();\n        $response = new Response('foo');\n        $response->setStatusCode(404);\n        $cache = $this->getCache(Request::create('/'), $response);\n        $esi->handle($cache, '/', '/alt', false);\n    }\n\n    public function testHandleWhenResponseIsNot200AndErrorsAreIgnored()\n    {\n        $esi = new Esi();\n        $response = new Response('foo');\n        $response->setStatusCode(404);\n        $cache = $this->getCache(Request::create('/'), $response);\n        $this->assertEquals('', $esi->handle($cache, '/', '/alt', true));\n    }\n\n    public function testHandleWhenResponseIsNot200AndAltIsPresent()\n    {\n        $esi = new Esi();\n        $response1 = new Response('foo');\n        $response1->setStatusCode(404);\n        $response2 = new Response('bar');\n        $cache = $this->getCache(Request::create('/'), [$response1, $response2]);\n        $this->assertEquals('bar', $esi->handle($cache, '/', '/alt', false));\n    }\n\n    public function testHandleWhenResponseIsNotModified()\n    {\n        $esi = new Esi();\n        $response = new Response('');\n        $response->setStatusCode(304);\n        $cache = $this->getCache(Request::create('/'), $response);\n        $this->assertEquals('', $esi->handle($cache, '/', '/alt', true));\n    }\n\n    protected function getCache($request, $response)\n    {\n        $cache = $this->getMockBuilder(HttpCache::class)->onlyMethods(['getRequest', 'handle'])->disableOriginalConstructor()->getMock();\n        $cache->expects($this->atLeastOnce())\n              ->method('getRequest')\n              ->willReturn($request)\n        ;\n        if (\\is_array($response)) {\n            $cache\n                  ->method('handle')\n                  ->willReturn(...$response)\n            ;\n        } else {\n            $cache\n                  ->method('handle')\n                  ->willReturn($response)\n            ;\n        }\n\n        return $cache;\n    }\n}\n"
  },
  {
    "path": "Tests/HttpCache/HttpCacheTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\HttpCache;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\Attributes\\Group;\nuse Symfony\\Component\\EventDispatcher\\EventDispatcher;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Event\\TerminateEvent;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\Esi;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\Store;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\StoreInterface;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\Kernel;\n\n#[Group('time-sensitive')]\nclass HttpCacheTest extends HttpCacheTestCase\n{\n    public function testTerminateDelegatesTerminationOnlyForTerminableInterface()\n    {\n        $storeMock = $this->createStub(StoreInterface::class);\n\n        // does not implement TerminableInterface\n        $kernel = new TestKernel();\n        $httpCache = new HttpCache($kernel, $storeMock);\n        $httpCache->terminate(Request::create('/'), new Response());\n\n        $this->assertFalse($kernel->terminateCalled, 'terminate() is never called if the kernel class does not implement TerminableInterface');\n\n        // implements TerminableInterface\n        $kernelMock = $this->getMockBuilder(Kernel::class)\n            ->disableOriginalConstructor()\n            ->onlyMethods(['terminate', 'registerBundles', 'registerContainerConfiguration'])\n            ->getMock();\n\n        $kernelMock->expects($this->once())\n            ->method('terminate');\n\n        $kernel = new HttpCache($kernelMock, $storeMock);\n        $kernel->terminate(Request::create('/'), new Response());\n    }\n\n    public function testDoesNotCallTerminateOnFreshResponse()\n    {\n        $terminateEvents = [];\n\n        $eventDispatcher = $this->createMock(EventDispatcher::class);\n        $eventDispatcher\n            ->expects($this->atLeastOnce())\n            ->method('dispatch')\n            ->with($this->callback(static function ($event) use (&$terminateEvents) {\n                if ($event instanceof TerminateEvent) {\n                    $terminateEvents[] = $event;\n                }\n\n                return true;\n            }));\n\n        $this->setNextResponse(\n            200,\n            [\n                'ETag' => '1234',\n                'Cache-Control' => 'public, s-maxage=60',\n            ],\n            'Hello World',\n            null,\n            $eventDispatcher\n        );\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n        $this->cache->terminate($this->request, $this->response);\n\n        sleep(2);\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsNotCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertTraceContains('fresh');\n        $this->assertEquals(2, $this->response->headers->get('Age'));\n        $this->cache->terminate($this->request, $this->response);\n\n        $this->assertCount(1, $terminateEvents);\n    }\n\n    public function testPassesOnNonGetHeadRequests()\n    {\n        $this->setNextResponse(200);\n        $this->request('POST', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertResponseOk();\n        $this->assertTraceContains('pass');\n        $this->assertFalse($this->response->headers->has('Age'));\n    }\n\n    public function testPassesSuspiciousMethodRequests()\n    {\n        $this->setNextResponse(200);\n        $this->request('POST', '/', ['HTTP_X-HTTP-Method-Override' => '__CONSTRUCT']);\n        $this->assertHttpKernelIsCalled();\n        $this->assertResponseOk();\n        $this->assertTraceNotContains('stale');\n        $this->assertTraceNotContains('invalid');\n        $this->assertFalse($this->response->headers->has('Age'));\n    }\n\n    public function testInvalidatesOnPostPutDeleteRequests()\n    {\n        foreach (['post', 'put', 'delete'] as $method) {\n            $this->setNextResponse(200);\n            $this->request($method, '/');\n\n            $this->assertHttpKernelIsCalled();\n            $this->assertResponseOk();\n            $this->assertTraceContains('invalidate');\n            $this->assertTraceContains('pass');\n        }\n    }\n\n    public function testDoesNotCacheWithAuthorizationRequestHeaderAndNonPublicResponse()\n    {\n        $this->setNextResponse(200, ['ETag' => '\"Foo\"']);\n        $this->request('GET', '/', ['HTTP_AUTHORIZATION' => 'basic foobarbaz']);\n\n        $this->assertHttpKernelIsCalled();\n        $this->assertResponseOk();\n        $this->assertEquals('private', $this->response->headers->get('Cache-Control'));\n\n        $this->assertTraceContains('miss');\n        $this->assertTraceNotContains('store');\n        $this->assertFalse($this->response->headers->has('Age'));\n    }\n\n    public function testDoesCacheWithAuthorizationRequestHeaderAndPublicResponse()\n    {\n        $this->setNextResponse(200, ['Cache-Control' => 'public', 'ETag' => '\"Foo\"']);\n        $this->request('GET', '/', ['HTTP_AUTHORIZATION' => 'basic foobarbaz']);\n\n        $this->assertHttpKernelIsCalled();\n        $this->assertResponseOk();\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n        $this->assertTrue($this->response->headers->has('Age'));\n        $this->assertEquals('public', $this->response->headers->get('Cache-Control'));\n    }\n\n    public function testDoesNotCacheWithCookieHeaderAndNonPublicResponse()\n    {\n        $this->setNextResponse(200, ['ETag' => '\"Foo\"']);\n        $this->request('GET', '/', [], ['foo' => 'bar']);\n\n        $this->assertHttpKernelIsCalled();\n        $this->assertResponseOk();\n        $this->assertEquals('private', $this->response->headers->get('Cache-Control'));\n        $this->assertTraceContains('miss');\n        $this->assertTraceNotContains('store');\n        $this->assertFalse($this->response->headers->has('Age'));\n    }\n\n    public function testDoesNotCacheRequestsWithACookieHeader()\n    {\n        $this->setNextResponse(200);\n        $this->request('GET', '/', [], ['foo' => 'bar']);\n\n        $this->assertHttpKernelIsCalled();\n        $this->assertResponseOk();\n        $this->assertEquals('private', $this->response->headers->get('Cache-Control'));\n        $this->assertTraceContains('miss');\n        $this->assertTraceNotContains('store');\n        $this->assertFalse($this->response->headers->has('Age'));\n    }\n\n    public function testRespondsWith304WhenIfModifiedSinceMatchesLastModified()\n    {\n        $time = \\DateTimeImmutable::createFromFormat('U', time());\n\n        $this->setNextResponse(200, ['Cache-Control' => 'public', 'Last-Modified' => $time->format(\\DATE_RFC2822), 'Content-Type' => 'text/plain'], 'Hello World');\n        $this->request('GET', '/', ['HTTP_IF_MODIFIED_SINCE' => $time->format(\\DATE_RFC2822)]);\n\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(304, $this->response->getStatusCode());\n        $this->assertEquals('', $this->response->headers->get('Content-Type'));\n        $this->assertSame('', $this->response->getContent());\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n    }\n\n    public function testRespondsWith304WhenIfNoneMatchMatchesETag()\n    {\n        $this->setNextResponse(200, ['Cache-Control' => 'public', 'ETag' => '12345', 'Content-Type' => 'text/plain'], 'Hello World');\n        $this->request('GET', '/', ['HTTP_IF_NONE_MATCH' => '12345']);\n\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(304, $this->response->getStatusCode());\n        $this->assertEquals('', $this->response->headers->get('Content-Type'));\n        $this->assertTrue($this->response->headers->has('ETag'));\n        $this->assertSame('', $this->response->getContent());\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n    }\n\n    public function testRespondsWith304WhenIfNoneMatchAndIfModifiedSinceBothMatch()\n    {\n        $time = \\DateTimeImmutable::createFromFormat('U', time());\n\n        $this->setNextResponse(200, [], '', static function ($request, $response) use ($time) {\n            $response->setStatusCode(200);\n            $response->headers->set('ETag', '12345');\n            $response->headers->set('Last-Modified', $time->format(\\DATE_RFC2822));\n            $response->headers->set('Content-Type', 'text/plain');\n            $response->setContent('Hello World');\n        });\n\n        // only ETag matches\n        $t = \\DateTimeImmutable::createFromFormat('U', time() - 3600);\n        $this->request('GET', '/', ['HTTP_IF_NONE_MATCH' => '12345', 'HTTP_IF_MODIFIED_SINCE' => $t->format(\\DATE_RFC2822)]);\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(304, $this->response->getStatusCode());\n\n        // only Last-Modified matches\n        $this->request('GET', '/', ['HTTP_IF_NONE_MATCH' => '1234', 'HTTP_IF_MODIFIED_SINCE' => $time->format(\\DATE_RFC2822)]);\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n\n        // Both matches\n        $this->request('GET', '/', ['HTTP_IF_NONE_MATCH' => '12345', 'HTTP_IF_MODIFIED_SINCE' => $time->format(\\DATE_RFC2822)]);\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(304, $this->response->getStatusCode());\n    }\n\n    public function testIncrementsMaxAgeWhenNoDateIsSpecifiedEventWhenUsingETag()\n    {\n        $this->setNextResponse(\n            200,\n            [\n                'ETag' => '1234',\n                'Cache-Control' => 'public, s-maxage=60',\n            ]\n        );\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n\n        sleep(2);\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsNotCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertTraceContains('fresh');\n        $this->assertEquals(2, $this->response->headers->get('Age'));\n    }\n\n    public function testValidatesPrivateResponsesCachedOnTheClient()\n    {\n        $this->setNextResponse(200, [], '', static function (Request $request, $response) {\n            $etags = preg_split('/\\s*,\\s*/', $request->headers->get('IF_NONE_MATCH', ''));\n            if ($request->cookies->has('authenticated')) {\n                $response->headers->set('Cache-Control', 'private, no-store');\n                $response->setETag('\"private tag\"');\n                if (\\in_array('\"private tag\"', $etags, true)) {\n                    $response->setStatusCode(304);\n                } else {\n                    $response->setStatusCode(200);\n                    $response->headers->set('Content-Type', 'text/plain');\n                    $response->setContent('private data');\n                }\n            } else {\n                $response->headers->set('Cache-Control', 'public');\n                $response->setETag('\"public tag\"');\n                if (\\in_array('\"public tag\"', $etags, true)) {\n                    $response->setStatusCode(304);\n                } else {\n                    $response->setStatusCode(200);\n                    $response->headers->set('Content-Type', 'text/plain');\n                    $response->setContent('public data');\n                }\n            }\n        });\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('\"public tag\"', $this->response->headers->get('ETag'));\n        $this->assertEquals('public data', $this->response->getContent());\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n\n        $this->request('GET', '/', [], ['authenticated' => '']);\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('\"private tag\"', $this->response->headers->get('ETag'));\n        $this->assertEquals('private data', $this->response->getContent());\n        $this->assertTraceContains('stale');\n        $this->assertTraceContains('invalid');\n        $this->assertTraceNotContains('store');\n    }\n\n    public function testStoresResponsesWhenNoCacheRequestDirectivePresent()\n    {\n        $time = \\DateTimeImmutable::createFromFormat('U', time() + 5);\n\n        $this->setNextResponse(200, ['Cache-Control' => 'public', 'Expires' => $time->format(\\DATE_RFC2822)]);\n        $this->request('GET', '/', ['HTTP_CACHE_CONTROL' => 'no-cache']);\n\n        $this->assertHttpKernelIsCalled();\n        $this->assertTraceContains('store');\n        $this->assertTrue($this->response->headers->has('Age'));\n    }\n\n    public function testReloadsResponsesWhenCacheHitsButNoCacheRequestDirectivePresentWhenAllowReloadIsSetTrue()\n    {\n        $count = 0;\n\n        $this->setNextResponse(200, ['Cache-Control' => 'public, max-age=10000'], '', static function ($request, $response) use (&$count) {\n            ++$count;\n            $response->setContent(1 == $count ? 'Hello World' : 'Goodbye World');\n        });\n\n        $this->request('GET', '/');\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('store');\n\n        $this->request('GET', '/');\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('fresh');\n\n        $this->cacheConfig['allow_reload'] = true;\n        $this->request('GET', '/', ['HTTP_CACHE_CONTROL' => 'no-cache']);\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Goodbye World', $this->response->getContent());\n        $this->assertTraceContains('reload');\n        $this->assertTraceContains('store');\n    }\n\n    public function testDoesNotReloadResponsesWhenAllowReloadIsSetFalseDefault()\n    {\n        $count = 0;\n\n        $this->setNextResponse(200, ['Cache-Control' => 'public, max-age=10000'], '', static function ($request, $response) use (&$count) {\n            ++$count;\n            $response->setContent(1 == $count ? 'Hello World' : 'Goodbye World');\n        });\n\n        $this->request('GET', '/');\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('store');\n\n        $this->request('GET', '/');\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('fresh');\n\n        $this->cacheConfig['allow_reload'] = false;\n        $this->request('GET', '/', ['HTTP_CACHE_CONTROL' => 'no-cache']);\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceNotContains('reload');\n\n        $this->request('GET', '/', ['HTTP_CACHE_CONTROL' => 'no-cache']);\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceNotContains('reload');\n    }\n\n    public function testRevalidatesFreshCacheEntryWhenMaxAgeRequestDirectiveIsExceededWhenAllowRevalidateOptionIsSetTrue()\n    {\n        $count = 0;\n\n        $this->setNextResponse(200, [], '', static function ($request, $response) use (&$count) {\n            ++$count;\n            $response->headers->set('Cache-Control', 'public, max-age=10000');\n            $response->setETag($count);\n            $response->setContent(1 == $count ? 'Hello World' : 'Goodbye World');\n        });\n\n        $this->request('GET', '/');\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('store');\n\n        $this->request('GET', '/');\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('fresh');\n\n        $this->cacheConfig['allow_revalidate'] = true;\n        $this->request('GET', '/', ['HTTP_CACHE_CONTROL' => 'max-age=0']);\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Goodbye World', $this->response->getContent());\n        $this->assertTraceContains('stale');\n        $this->assertTraceContains('invalid');\n        $this->assertTraceContains('store');\n    }\n\n    public function testDoesNotRevalidateFreshCacheEntryWhenEnableRevalidateOptionIsSetFalseDefault()\n    {\n        $count = 0;\n\n        $this->setNextResponse(200, [], '', static function ($request, $response) use (&$count) {\n            ++$count;\n            $response->headers->set('Cache-Control', 'public, max-age=10000');\n            $response->setETag($count);\n            $response->setContent(1 == $count ? 'Hello World' : 'Goodbye World');\n        });\n\n        $this->request('GET', '/');\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('store');\n\n        $this->request('GET', '/');\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('fresh');\n\n        $this->cacheConfig['allow_revalidate'] = false;\n        $this->request('GET', '/', ['HTTP_CACHE_CONTROL' => 'max-age=0']);\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceNotContains('stale');\n        $this->assertTraceNotContains('invalid');\n        $this->assertTraceContains('fresh');\n\n        $this->request('GET', '/', ['HTTP_CACHE_CONTROL' => 'max-age=0']);\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceNotContains('stale');\n        $this->assertTraceNotContains('invalid');\n        $this->assertTraceContains('fresh');\n    }\n\n    public function testFetchesResponseFromBackendWhenCacheMisses()\n    {\n        $time = \\DateTimeImmutable::createFromFormat('U', time() + 5);\n        $this->setNextResponse(200, ['Cache-Control' => 'public', 'Expires' => $time->format(\\DATE_RFC2822)]);\n\n        $this->request('GET', '/');\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertTraceContains('miss');\n        $this->assertTrue($this->response->headers->has('Age'));\n    }\n\n    public function testDoesNotCacheSomeStatusCodeResponses()\n    {\n        foreach (array_merge(range(201, 202), range(204, 206), range(303, 305), range(400, 403), range(405, 409), range(411, 417), range(500, 505)) as $code) {\n            $time = \\DateTimeImmutable::createFromFormat('U', time() + 5);\n            $this->setNextResponse($code, ['Expires' => $time->format(\\DATE_RFC2822)]);\n\n            $this->request('GET', '/');\n            $this->assertEquals($code, $this->response->getStatusCode());\n            $this->assertTraceNotContains('store');\n            $this->assertFalse($this->response->headers->has('Age'));\n        }\n    }\n\n    public function testDoesNotCacheResponsesWithExplicitNoStoreDirective()\n    {\n        $time = \\DateTimeImmutable::createFromFormat('U', time() + 5);\n        $this->setNextResponse(200, ['Expires' => $time->format(\\DATE_RFC2822), 'Cache-Control' => 'no-store']);\n\n        $this->request('GET', '/');\n        $this->assertTraceNotContains('store');\n        $this->assertFalse($this->response->headers->has('Age'));\n    }\n\n    public function testDoesNotCacheResponsesWithoutFreshnessInformationOrAValidator()\n    {\n        $this->setNextResponse();\n\n        $this->request('GET', '/');\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertTraceNotContains('store');\n    }\n\n    public function testCachesResponsesWithExplicitNoCacheDirective()\n    {\n        $time = \\DateTimeImmutable::createFromFormat('U', time() + 5);\n        $this->setNextResponse(200, ['Expires' => $time->format(\\DATE_RFC2822), 'Cache-Control' => 'public, no-cache']);\n\n        $this->request('GET', '/');\n        $this->assertTraceContains('store');\n        $this->assertTrue($this->response->headers->has('Age'));\n    }\n\n    public function testRevalidatesResponsesWithNoCacheDirectiveEvenIfFresh()\n    {\n        $this->setNextResponse(200, ['Cache-Control' => 'public, no-cache, max-age=10', 'ETag' => 'some-etag'], 'OK');\n        $this->request('GET', '/'); // warm the cache\n\n        sleep(5);\n\n        $this->setNextResponse(304, ['Cache-Control' => 'public, no-cache, max-age=10', 'ETag' => 'some-etag']);\n        $this->request('GET', '/');\n\n        $this->assertHttpKernelIsCalled(); // no-cache -> MUST have revalidated at origin\n        $this->assertTraceContains('valid');\n        $this->assertEquals('OK', $this->response->getContent());\n        $this->assertEquals(0, $this->response->getAge());\n    }\n\n    public function testCachesResponsesWithAnExpirationHeader()\n    {\n        $time = \\DateTimeImmutable::createFromFormat('U', time() + 5);\n        $this->setNextResponse(200, ['Cache-Control' => 'public', 'Expires' => $time->format(\\DATE_RFC2822)]);\n\n        $this->request('GET', '/');\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertNotNull($this->response->headers->get('Date'));\n        $this->assertNotNull($this->response->headers->get('X-Content-Digest'));\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n\n        $values = $this->getMetaStorageValues();\n        $this->assertCount(1, $values);\n    }\n\n    public function testCachesResponsesWithAMaxAgeDirective()\n    {\n        $this->setNextResponse(200, ['Cache-Control' => 'public, max-age=5']);\n\n        $this->request('GET', '/');\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertNotNull($this->response->headers->get('Date'));\n        $this->assertNotNull($this->response->headers->get('X-Content-Digest'));\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n\n        $values = $this->getMetaStorageValues();\n        $this->assertCount(1, $values);\n    }\n\n    public function testCachesResponsesWithASMaxAgeDirective()\n    {\n        $this->setNextResponse(200, ['Cache-Control' => 's-maxage=5']);\n\n        $this->request('GET', '/');\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertNotNull($this->response->headers->get('Date'));\n        $this->assertNotNull($this->response->headers->get('X-Content-Digest'));\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n\n        $values = $this->getMetaStorageValues();\n        $this->assertCount(1, $values);\n    }\n\n    public function testCachesResponsesWithALastModifiedValidatorButNoFreshnessInformation()\n    {\n        $time = \\DateTimeImmutable::createFromFormat('U', time());\n        $this->setNextResponse(200, ['Cache-Control' => 'public', 'Last-Modified' => $time->format(\\DATE_RFC2822)]);\n\n        $this->request('GET', '/');\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n    }\n\n    public function testCachesResponsesWithAnETagValidatorButNoFreshnessInformation()\n    {\n        $this->setNextResponse(200, ['Cache-Control' => 'public', 'ETag' => '\"123456\"']);\n\n        $this->request('GET', '/');\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n    }\n\n    public function testHitsCachedResponsesWithExpiresHeader()\n    {\n        $time1 = \\DateTimeImmutable::createFromFormat('U', time() - 5);\n        $time2 = \\DateTimeImmutable::createFromFormat('U', time() + 5);\n        $this->setNextResponse(200, ['Cache-Control' => 'public', 'Date' => $time1->format(\\DATE_RFC2822), 'Expires' => $time2->format(\\DATE_RFC2822)]);\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertNotNull($this->response->headers->get('Date'));\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n        $this->assertEquals('Hello World', $this->response->getContent());\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsNotCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertLessThan(2, strtotime($this->responses[0]->headers->get('Date')) - strtotime($this->response->headers->get('Date')));\n        $this->assertGreaterThan(0, $this->response->headers->get('Age'));\n        $this->assertNotNull($this->response->headers->get('X-Content-Digest'));\n        $this->assertTraceContains('fresh');\n        $this->assertTraceNotContains('store');\n        $this->assertEquals('Hello World', $this->response->getContent());\n    }\n\n    public function testHitsCachedResponseWithMaxAgeDirective()\n    {\n        $time = \\DateTimeImmutable::createFromFormat('U', time() - 5);\n        $this->setNextResponse(200, ['Date' => $time->format(\\DATE_RFC2822), 'Cache-Control' => 'public, max-age=10']);\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertNotNull($this->response->headers->get('Date'));\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n        $this->assertEquals('Hello World', $this->response->getContent());\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsNotCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertLessThan(2, strtotime($this->responses[0]->headers->get('Date')) - strtotime($this->response->headers->get('Date')));\n        $this->assertGreaterThan(0, $this->response->headers->get('Age'));\n        $this->assertNotNull($this->response->headers->get('X-Content-Digest'));\n        $this->assertTraceContains('fresh');\n        $this->assertTraceNotContains('store');\n        $this->assertEquals('Hello World', $this->response->getContent());\n    }\n\n    public function testDegradationWhenCacheLocked()\n    {\n        if ('\\\\' === \\DIRECTORY_SEPARATOR) {\n            $this->markTestSkipped('Skips on windows to avoid permissions issues.');\n        }\n\n        $this->cacheConfig['stale_while_revalidate'] = 10;\n\n        // The presence of Last-Modified makes this cacheable (because Response::isValidateable() then).\n        $this->setNextResponse(200, ['Cache-Control' => 'public, s-maxage=5', 'Last-Modified' => 'some while ago'], 'Old response');\n        $this->request('GET', '/'); // warm the cache\n\n        // Now, lock the cache\n        $concurrentRequest = Request::create('/', 'GET');\n        $this->store->lock($concurrentRequest);\n\n        /*\n         *  After 10s, the cached response has become stale. Yet, we're still within the \"stale_while_revalidate\"\n         *  timeout so we may serve the stale response.\n         */\n        sleep(10);\n\n        $this->store = $this->createStore(); // create another store instance that does not hold the current lock\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsNotCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertTraceContains('stale-while-revalidate');\n        $this->assertEquals('Old response', $this->response->getContent());\n\n        /*\n         * Another 10s later, stale_while_revalidate is over. Resort to serving the old response, but\n         * do so with a \"server unavailable\" message.\n         */\n        sleep(10);\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsNotCalled();\n        $this->assertEquals(503, $this->response->getStatusCode());\n        $this->assertEquals('Old response', $this->response->getContent());\n    }\n\n    public function testHitBackendOnlyOnceWhenCacheWasLocked()\n    {\n        // Disable stale-while-revalidate, it circumvents waiting for the lock\n        $this->cacheConfig['stale_while_revalidate'] = 0;\n\n        $this->setNextResponses([\n            [\n                'status' => 200,\n                'body' => 'initial response',\n                'headers' => [\n                    'Cache-Control' => 'public, no-cache',\n                    'Last-Modified' => 'some while ago',\n                ],\n            ],\n            [\n                'status' => 304,\n                'body' => '',\n                'headers' => [\n                    'Cache-Control' => 'public, no-cache',\n                    'Last-Modified' => 'some while ago',\n                ],\n            ],\n            [\n                'status' => 500,\n                'body' => 'The backend should not be called twice during revalidation',\n                'headers' => [],\n            ],\n        ]);\n\n        $this->request('GET', '/'); // warm the cache\n\n        // Use a store that simulates a cache entry being locked upon first attempt\n        $this->store = new class(sys_get_temp_dir().'/http_cache') extends Store {\n            private bool $hasLock = false;\n\n            public function lock(Request $request): bool\n            {\n                $hasLock = $this->hasLock;\n                $this->hasLock = true;\n\n                return $hasLock;\n            }\n\n            public function isLocked(Request $request): bool\n            {\n                return false;\n            }\n        };\n\n        $this->request('GET', '/'); // hit the cache with simulated lock/concurrency block\n\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('initial response', $this->response->getContent());\n\n        $traces = $this->cache->getTraces();\n        $this->assertSame(['waiting', 'stale', 'valid', 'store'], current($traces));\n    }\n\n    public function testTraceAddedWhenCacheLocked()\n    {\n        if ('\\\\' === \\DIRECTORY_SEPARATOR) {\n            $this->markTestSkipped('Skips on windows to avoid permissions issues.');\n        }\n\n        // Disable stale-while-revalidate, which circumvents blocking access\n        $this->cacheConfig['stale_while_revalidate'] = 0;\n\n        // The presence of Last-Modified makes this cacheable\n        $this->setNextResponse(200, ['Cache-Control' => 'public, no-cache', 'Last-Modified' => 'some while ago'], 'Old response');\n        $this->request('GET', '/'); // warm the cache\n\n        $primedStore = $this->store;\n\n        $this->store = $this->createStub(Store::class);\n        $this->store->method('lookup')->willReturnCallback(static fn (Request $request) => $primedStore->lookup($request));\n        // Assume the cache is locked at the first attempt, but immediately treat the lock as released afterwards\n        $this->store->method('lock')->willReturnOnConsecutiveCalls(false, true);\n        $this->store->method('isLocked')->willReturn(false);\n\n        $this->request('GET', '/');\n\n        $this->assertTraceContains('waiting');\n    }\n\n    public function testHitsCachedResponseWithSMaxAgeDirective()\n    {\n        $time = \\DateTimeImmutable::createFromFormat('U', time() - 5);\n        $this->setNextResponse(200, ['Date' => $time->format(\\DATE_RFC2822), 'Cache-Control' => 's-maxage=10, max-age=0']);\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertNotNull($this->response->headers->get('Date'));\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n        $this->assertEquals('Hello World', $this->response->getContent());\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsNotCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertLessThan(2, strtotime($this->responses[0]->headers->get('Date')) - strtotime($this->response->headers->get('Date')));\n        $this->assertGreaterThan(0, $this->response->headers->get('Age'));\n        $this->assertNotNull($this->response->headers->get('X-Content-Digest'));\n        $this->assertTraceContains('fresh');\n        $this->assertTraceNotContains('store');\n        $this->assertEquals('Hello World', $this->response->getContent());\n    }\n\n    public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformation()\n    {\n        $this->setNextResponse();\n\n        $this->cacheConfig['default_ttl'] = 10;\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertMatchesRegularExpression('/s-maxage=10/', $this->response->headers->get('Cache-Control'));\n\n        $this->cacheConfig['default_ttl'] = 10;\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsNotCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertTraceContains('fresh');\n        $this->assertTraceNotContains('store');\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertMatchesRegularExpression('/s-maxage=10/', $this->response->headers->get('Cache-Control'));\n    }\n\n    public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformationAndAfterTtlWasExpired()\n    {\n        $this->setNextResponse();\n\n        $this->cacheConfig['default_ttl'] = 2;\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control'));\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsNotCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertTraceContains('fresh');\n        $this->assertTraceNotContains('store');\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control'));\n\n        // expires the cache\n        $values = $this->getMetaStorageValues();\n        $this->assertCount(1, $values);\n        $tmp = unserialize($values[0]);\n        $time = \\DateTimeImmutable::createFromFormat('U', time() - 5);\n        $tmp[0][1]['date'] = $time->format(\\DATE_RFC2822);\n        $r = new \\ReflectionObject($this->store);\n        $m = $r->getMethod('save');\n        $m->invoke($this->store, 'md'.hash('sha256', 'http://localhost/'), serialize($tmp));\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertTraceContains('stale');\n        $this->assertTraceContains('invalid');\n        $this->assertTraceContains('store');\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control'));\n\n        $this->setNextResponse();\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsNotCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertTraceContains('fresh');\n        $this->assertTraceNotContains('store');\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control'));\n    }\n\n    public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformationAndAfterTtlWasExpiredWithStatus304()\n    {\n        $this->setNextResponse();\n\n        $this->cacheConfig['default_ttl'] = 2;\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control'));\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsNotCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertTraceContains('fresh');\n        $this->assertTraceNotContains('store');\n        $this->assertEquals('Hello World', $this->response->getContent());\n\n        // expires the cache\n        $values = $this->getMetaStorageValues();\n        $this->assertCount(1, $values);\n        $tmp = unserialize($values[0]);\n        $time = \\DateTimeImmutable::createFromFormat('U', time() - 5);\n        $tmp[0][1]['date'] = $time->format(\\DATE_RFC2822);\n        $r = new \\ReflectionObject($this->store);\n        $m = $r->getMethod('save');\n        $m->invoke($this->store, 'md'.hash('sha256', 'http://localhost/'), serialize($tmp));\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertTraceContains('stale');\n        $this->assertTraceContains('valid');\n        $this->assertTraceContains('store');\n        $this->assertTraceNotContains('miss');\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control'));\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsNotCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertTraceContains('fresh');\n        $this->assertTraceNotContains('store');\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control'));\n    }\n\n    public function testDoesNotAssignDefaultTtlWhenResponseHasMustRevalidateDirective()\n    {\n        $this->setNextResponse(200, ['Cache-Control' => 'must-revalidate']);\n\n        $this->cacheConfig['default_ttl'] = 10;\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertTraceContains('miss');\n        $this->assertTraceNotContains('store');\n        $this->assertDoesNotMatchRegularExpression('/s-maxage/', $this->response->headers->get('Cache-Control'));\n        $this->assertEquals('Hello World', $this->response->getContent());\n    }\n\n    public function testFetchesFullResponseWhenCacheStaleAndNoValidatorsPresent()\n    {\n        $time = \\DateTimeImmutable::createFromFormat('U', time() + 5);\n        $this->setNextResponse(200, ['Cache-Control' => 'public', 'Expires' => $time->format(\\DATE_RFC2822)]);\n\n        // build initial request\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertNotNull($this->response->headers->get('Date'));\n        $this->assertNotNull($this->response->headers->get('X-Content-Digest'));\n        $this->assertNotNull($this->response->headers->get('Age'));\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n        $this->assertEquals('Hello World', $this->response->getContent());\n\n        // go in and play around with the cached metadata directly ...\n        $values = $this->getMetaStorageValues();\n        $this->assertCount(1, $values);\n        $tmp = unserialize($values[0]);\n        $time = \\DateTimeImmutable::createFromFormat('U', time());\n        $tmp[0][1]['expires'] = $time->format(\\DATE_RFC2822);\n        $r = new \\ReflectionObject($this->store);\n        $m = $r->getMethod('save');\n        $m->invoke($this->store, 'md'.hash('sha256', 'http://localhost/'), serialize($tmp));\n\n        // build subsequent request; should be found but miss due to freshness\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertLessThanOrEqual(1, $this->response->headers->get('Age'));\n        $this->assertNotNull($this->response->headers->get('X-Content-Digest'));\n        $this->assertTraceContains('stale');\n        $this->assertTraceNotContains('fresh');\n        $this->assertTraceNotContains('miss');\n        $this->assertTraceContains('store');\n        $this->assertEquals('Hello World', $this->response->getContent());\n    }\n\n    public function testValidatesCachedResponsesWithLastModifiedAndNoFreshnessInformation()\n    {\n        $time = \\DateTimeImmutable::createFromFormat('U', time());\n        $this->setNextResponse(200, [], 'Hello World', static function ($request, $response) use ($time) {\n            $response->headers->set('Cache-Control', 'public');\n            $response->headers->set('Last-Modified', $time->format(\\DATE_RFC2822));\n            if ($time->format(\\DATE_RFC2822) == $request->headers->get('IF_MODIFIED_SINCE')) {\n                $response->setStatusCode(304);\n                $response->setContent('');\n            }\n        });\n\n        // build initial request\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertNotNull($this->response->headers->get('Last-Modified'));\n        $this->assertNotNull($this->response->headers->get('X-Content-Digest'));\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n        $this->assertTraceNotContains('stale');\n\n        // build subsequent request; should be found but miss due to freshness\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertNotNull($this->response->headers->get('Last-Modified'));\n        $this->assertNotNull($this->response->headers->get('X-Content-Digest'));\n        $this->assertLessThanOrEqual(1, $this->response->headers->get('Age'));\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('stale');\n        $this->assertTraceContains('valid');\n        $this->assertTraceContains('store');\n        $this->assertTraceNotContains('miss');\n    }\n\n    public function testValidatesCachedResponsesUseSameHttpMethod()\n    {\n        $this->setNextResponse(200, [], 'Hello World', function ($request, $response) {\n            $this->assertSame('OPTIONS', $request->getMethod());\n        });\n\n        // build initial request\n        $this->request('OPTIONS', '/');\n\n        // build subsequent request\n        $this->request('OPTIONS', '/');\n    }\n\n    public function testValidatesCachedResponsesWithETagAndNoFreshnessInformation()\n    {\n        $this->setNextResponse(200, [], 'Hello World', function ($request, $response) {\n            $this->assertFalse($request->headers->has('If-Modified-Since'));\n            $response->headers->set('Cache-Control', 'public');\n            $response->headers->set('ETag', '\"12345\"');\n            if ($response->getETag() == $request->headers->get('IF_NONE_MATCH')) {\n                $response->setStatusCode(304);\n                $response->setContent('');\n            }\n        });\n\n        // build initial request\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertNotNull($this->response->headers->get('ETag'));\n        $this->assertNotNull($this->response->headers->get('X-Content-Digest'));\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n\n        // build subsequent request; should be found but miss due to freshness\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertNotNull($this->response->headers->get('ETag'));\n        $this->assertNotNull($this->response->headers->get('X-Content-Digest'));\n        $this->assertLessThanOrEqual(1, $this->response->headers->get('Age'));\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('stale');\n        $this->assertTraceContains('valid');\n        $this->assertTraceContains('store');\n        $this->assertTraceNotContains('miss');\n    }\n\n    public function testServesResponseWhileFreshAndRevalidatesWithLastModifiedInformation()\n    {\n        $time = \\DateTimeImmutable::createFromFormat('U', time());\n\n        $this->setNextResponse(200, [], 'Hello World', static function (Request $request, Response $response) use ($time) {\n            $response->setSharedMaxAge(10);\n            $response->headers->set('Last-Modified', $time->format(\\DATE_RFC2822));\n        });\n\n        // prime the cache\n        $this->request('GET', '/');\n\n        // next request before s-maxage has expired: Serve from cache\n        // without hitting the backend\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsNotCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('fresh');\n\n        sleep(15); // expire the cache\n\n        $this->setNextResponse(304, [], '', function (Request $request, Response $response) use ($time) {\n            $this->assertEquals($time->format(\\DATE_RFC2822), $request->headers->get('IF_MODIFIED_SINCE'));\n        });\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('stale');\n        $this->assertTraceContains('valid');\n    }\n\n    public function testReplacesCachedResponsesWhenValidationResultsInNon304Response()\n    {\n        $time = \\DateTimeImmutable::createFromFormat('U', time());\n        $count = 0;\n        $this->setNextResponse(200, [], 'Hello World', static function ($request, $response) use ($time, &$count) {\n            $response->headers->set('Last-Modified', $time->format(\\DATE_RFC2822));\n            $response->headers->set('Cache-Control', 'public');\n            switch (++$count) {\n                case 1:\n                    $response->setContent('first response');\n                    break;\n                case 2:\n                    $response->setContent('second response');\n                    break;\n                case 3:\n                    $response->setContent('');\n                    $response->setStatusCode(304);\n                    break;\n            }\n        });\n\n        // first request should fetch from backend and store in cache\n        $this->request('GET', '/');\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('first response', $this->response->getContent());\n\n        // second request is validated, is invalid, and replaces cached entry\n        $this->request('GET', '/');\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('second response', $this->response->getContent());\n\n        // third response is validated, valid, and returns cached entry\n        $this->request('GET', '/');\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('second response', $this->response->getContent());\n\n        $this->assertEquals(3, $count);\n    }\n\n    public function testPassesHeadRequestsThroughDirectlyOnPass()\n    {\n        $this->setNextResponse(200, [], 'Hello World', function ($request, $response) {\n            $response->setContent('');\n            $response->setStatusCode(200);\n            $this->assertEquals('HEAD', $request->getMethod());\n        });\n\n        $this->request('HEAD', '/', ['HTTP_EXPECT' => 'something ...']);\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals('', $this->response->getContent());\n    }\n\n    public function testUsesCacheToRespondToHeadRequestsWhenFresh()\n    {\n        $this->setNextResponse(200, [], 'Hello World', function ($request, $response) {\n            $response->headers->set('Cache-Control', 'public, max-age=10');\n            $response->setContent('Hello World');\n            $response->setStatusCode(200);\n            $this->assertNotEquals('HEAD', $request->getMethod());\n        });\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals('Hello World', $this->response->getContent());\n\n        $this->request('HEAD', '/');\n        $this->assertHttpKernelIsNotCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('', $this->response->getContent());\n        $this->assertEquals(\\strlen('Hello World'), $this->response->headers->get('Content-Length'));\n    }\n\n    public function testSendsNoContentWhenFresh()\n    {\n        $time = \\DateTimeImmutable::createFromFormat('U', time());\n        $this->setNextResponse(200, [], 'Hello World', static function ($request, $response) use ($time) {\n            $response->headers->set('Cache-Control', 'public, max-age=10');\n            $response->headers->set('Last-Modified', $time->format(\\DATE_RFC2822));\n        });\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals('Hello World', $this->response->getContent());\n\n        $this->request('GET', '/', ['HTTP_IF_MODIFIED_SINCE' => $time->format(\\DATE_RFC2822)]);\n        $this->assertHttpKernelIsNotCalled();\n        $this->assertEquals(304, $this->response->getStatusCode());\n        $this->assertEquals('', $this->response->getContent());\n    }\n\n    public function testInvalidatesCachedResponsesOnPost()\n    {\n        $this->setNextResponse(200, [], 'Hello World', static function ($request, $response) {\n            if ('GET' == $request->getMethod()) {\n                $response->setStatusCode(200);\n                $response->headers->set('Cache-Control', 'public, max-age=500');\n                $response->setContent('Hello World');\n            } elseif ('POST' == $request->getMethod()) {\n                $response->setStatusCode(303);\n                $response->headers->set('Location', '/');\n                $response->headers->remove('Cache-Control');\n                $response->setContent('');\n            }\n        });\n\n        // build initial request to enter into the cache\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n\n        // make sure it is valid\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsNotCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('fresh');\n\n        // now POST to same URL\n        $this->request('POST', '/helloworld');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals('/', $this->response->headers->get('Location'));\n        $this->assertTraceContains('invalidate');\n        $this->assertTraceContains('pass');\n        $this->assertEquals('', $this->response->getContent());\n\n        // now make sure it was actually invalidated\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Hello World', $this->response->getContent());\n        $this->assertTraceContains('stale');\n        $this->assertTraceContains('invalid');\n        $this->assertTraceContains('store');\n    }\n\n    public function testServesFromCacheWhenHeadersMatch()\n    {\n        $count = 0;\n        $this->setNextResponse(200, ['Cache-Control' => 'max-age=10000'], '', static function ($request, $response) use (&$count) {\n            $response->headers->set('Vary', 'Accept User-Agent Foo');\n            $response->headers->set('Cache-Control', 'public, max-age=10');\n            $response->headers->set('X-Response-Count', ++$count);\n            $response->setContent($request->headers->get('USER_AGENT'));\n        });\n\n        $this->request('GET', '/', ['HTTP_ACCEPT' => 'text/html', 'HTTP_USER_AGENT' => 'Bob/1.0']);\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Bob/1.0', $this->response->getContent());\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n\n        $this->request('GET', '/', ['HTTP_ACCEPT' => 'text/html', 'HTTP_USER_AGENT' => 'Bob/1.0']);\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Bob/1.0', $this->response->getContent());\n        $this->assertTraceContains('fresh');\n        $this->assertTraceNotContains('store');\n        $this->assertNotNull($this->response->headers->get('X-Content-Digest'));\n    }\n\n    public function testStoresMultipleResponsesWhenHeadersDiffer()\n    {\n        $count = 0;\n        $this->setNextResponse(200, ['Cache-Control' => 'max-age=10000'], '', static function ($request, $response) use (&$count) {\n            $response->headers->set('Vary', 'Accept User-Agent Foo');\n            $response->headers->set('Cache-Control', 'public, max-age=10');\n            $response->headers->set('X-Response-Count', ++$count);\n            $response->setContent($request->headers->get('USER_AGENT'));\n        });\n\n        $this->request('GET', '/', ['HTTP_ACCEPT' => 'text/html', 'HTTP_USER_AGENT' => 'Bob/1.0']);\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('Bob/1.0', $this->response->getContent());\n        $this->assertEquals(1, $this->response->headers->get('X-Response-Count'));\n\n        $this->request('GET', '/', ['HTTP_ACCEPT' => 'text/html', 'HTTP_USER_AGENT' => 'Bob/2.0']);\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertTraceContains('miss');\n        $this->assertTraceContains('store');\n        $this->assertEquals('Bob/2.0', $this->response->getContent());\n        $this->assertEquals(2, $this->response->headers->get('X-Response-Count'));\n\n        $this->request('GET', '/', ['HTTP_ACCEPT' => 'text/html', 'HTTP_USER_AGENT' => 'Bob/1.0']);\n        $this->assertTraceContains('fresh');\n        $this->assertEquals('Bob/1.0', $this->response->getContent());\n        $this->assertEquals(1, $this->response->headers->get('X-Response-Count'));\n\n        $this->request('GET', '/', ['HTTP_ACCEPT' => 'text/html', 'HTTP_USER_AGENT' => 'Bob/2.0']);\n        $this->assertTraceContains('fresh');\n        $this->assertEquals('Bob/2.0', $this->response->getContent());\n        $this->assertEquals(2, $this->response->headers->get('X-Response-Count'));\n\n        $this->request('GET', '/', ['HTTP_USER_AGENT' => 'Bob/2.0']);\n        $this->assertTraceContains('miss');\n        $this->assertEquals('Bob/2.0', $this->response->getContent());\n        $this->assertEquals(3, $this->response->headers->get('X-Response-Count'));\n    }\n\n    public function testShouldCatchExceptions()\n    {\n        $this->catchExceptions();\n\n        $this->setNextResponse();\n        $this->request('GET', '/');\n\n        $this->assertExceptionsAreCaught();\n    }\n\n    public function testShouldCatchExceptionsWhenReloadingAndNoCacheRequest()\n    {\n        $this->catchExceptions();\n\n        $this->setNextResponse();\n        $this->cacheConfig['allow_reload'] = true;\n        $this->request('GET', '/', [], [], false, ['Pragma' => 'no-cache']);\n\n        $this->assertExceptionsAreCaught();\n    }\n\n    public function testShouldNotCatchExceptions()\n    {\n        $this->catchExceptions(false);\n\n        $this->setNextResponse();\n        $this->request('GET', '/');\n\n        $this->assertExceptionsAreNotCaught();\n    }\n\n    public function testEsiCacheSendsTheLowestTtl()\n    {\n        $responses = [\n            [\n                'status' => 200,\n                'body' => '<esi:include src=\"/foo\" /> <esi:include src=\"/bar\" />',\n                'headers' => [\n                    'Cache-Control' => 's-maxage=300',\n                    'Surrogate-Control' => 'content=\"ESI/1.0\"',\n                ],\n            ],\n            [\n                'status' => 200,\n                'body' => 'Hello World!',\n                'headers' => ['Cache-Control' => 's-maxage=200'],\n            ],\n            [\n                'status' => 200,\n                'body' => 'My name is Bobby.',\n                'headers' => ['Cache-Control' => 's-maxage=100'],\n            ],\n        ];\n\n        $this->setNextResponses($responses);\n\n        $this->request('GET', '/', [], [], true);\n        $this->assertEquals('Hello World! My name is Bobby.', $this->response->getContent());\n\n        $this->assertEquals(100, $this->response->getTtl());\n    }\n\n    public function testEsiCacheSendsTheLowestTtlForHeadRequests()\n    {\n        $responses = [\n            [\n                'status' => 200,\n                'body' => 'I am a long-lived main response, but I embed a short-lived resource: <esi:include src=\"/foo\" />',\n                'headers' => [\n                    'Cache-Control' => 's-maxage=300',\n                    'Surrogate-Control' => 'content=\"ESI/1.0\"',\n                ],\n            ],\n            [\n                'status' => 200,\n                'body' => 'I am a short-lived resource',\n                'headers' => ['Cache-Control' => 's-maxage=100'],\n            ],\n        ];\n\n        $this->setNextResponses($responses);\n\n        $this->request('HEAD', '/', [], [], true);\n\n        $this->assertSame('', $this->response->getContent());\n        $this->assertEquals(100, $this->response->getTtl());\n    }\n\n    public function testEsiCacheIncludesEmbeddedResponseContentWhenMainResponseFailsRevalidationAndEmbeddedResponseIsFresh()\n    {\n        $this->setNextResponses([\n            [\n                'status' => 200,\n                'body' => 'main <esi:include src=\"/foo\" />',\n                'headers' => [\n                    'Cache-Control' => 's-maxage=0', // goes stale immediately\n                    'Surrogate-Control' => 'content=\"ESI/1.0\"',\n                    'Last-Modified' => 'Mon, 12 Aug 2024 10:00:00 +0000',\n                ],\n            ],\n            [\n                'status' => 200,\n                'body' => 'embedded',\n                'headers' => [\n                    'Cache-Control' => 's-maxage=10', // stays fresh\n                    'Last-Modified' => 'Mon, 12 Aug 2024 10:05:00 +0000',\n                ],\n            ],\n        ]);\n\n        // prime the cache\n        $this->request('GET', '/', [], [], true);\n        $this->assertSame(200, $this->response->getStatusCode());\n        $this->assertSame('main embedded', $this->response->getContent());\n        $this->assertSame('Mon, 12 Aug 2024 10:05:00 +0000', $this->response->getLastModified()->format(\\DATE_RFC2822)); // max of both values\n\n        $this->setNextResponses([\n            [\n                // On the next request, the main response has an updated Last-Modified (main page was modified)...\n                'status' => 200,\n                'body' => 'main <esi:include src=\"/foo\" />',\n                'headers' => [\n                    'Cache-Control' => 's-maxage=0',\n                    'Surrogate-Control' => 'content=\"ESI/1.0\"',\n                    'Last-Modified' => 'Mon, 12 Aug 2024 10:10:00 +0000',\n                ],\n            ],\n            // no revalidation request happens for the embedded response, since it is still fresh\n        ]);\n\n        // Re-request with Last-Modified time that we received when the cache was primed\n        $this->request('GET', '/', ['HTTP_IF_MODIFIED_SINCE' => 'Mon, 12 Aug 2024 10:05:00 +0000'], [], true);\n\n        $this->assertSame(200, $this->response->getStatusCode());\n\n        // The cache should use the content (\"embedded\") from the cached entry\n        $this->assertSame('main embedded', $this->response->getContent());\n\n        $traces = $this->cache->getTraces();\n        $this->assertSame(['stale', 'invalid', 'store'], $traces['GET /']);\n\n        // The embedded resource was still fresh\n        $this->assertSame(['fresh'], $traces['GET /foo']);\n    }\n\n    public function testEsiCacheIncludesEmbeddedResponseContentWhenMainResponseFailsRevalidationAndEmbeddedResponseIsValid()\n    {\n        $this->setNextResponses([\n            [\n                'status' => 200,\n                'body' => 'main <esi:include src=\"/foo\" />',\n                'headers' => [\n                    'Cache-Control' => 's-maxage=0', // goes stale immediately\n                    'Surrogate-Control' => 'content=\"ESI/1.0\"',\n                    'Last-Modified' => 'Mon, 12 Aug 2024 10:00:00 +0000',\n                ],\n            ],\n            [\n                'status' => 200,\n                'body' => 'embedded',\n                'headers' => [\n                    'Cache-Control' => 's-maxage=0', // goes stale immediately\n                    'Last-Modified' => 'Mon, 12 Aug 2024 10:05:00 +0000',\n                ],\n            ],\n        ]);\n\n        // prime the cache\n        $this->request('GET', '/', [], [], true);\n        $this->assertSame(200, $this->response->getStatusCode());\n        $this->assertSame('main embedded', $this->response->getContent());\n        $this->assertSame('Mon, 12 Aug 2024 10:05:00 +0000', $this->response->getLastModified()->format(\\DATE_RFC2822)); // max of both values\n\n        $this->setNextResponses([\n            [\n                // On the next request, the main response has an updated Last-Modified (main page was modified)...\n                'status' => 200,\n                'body' => 'main <esi:include src=\"/foo\" />',\n                'headers' => [\n                    'Cache-Control' => 's-maxage=0',\n                    'Surrogate-Control' => 'content=\"ESI/1.0\"',\n                    'Last-Modified' => 'Mon, 12 Aug 2024 10:10:00 +0000',\n                ],\n            ],\n            [\n                // We have a stale cache entry for the embedded response which will be revalidated.\n                // Let's assume the resource did not change, so the controller sends a 304 without content body.\n                'status' => 304,\n                'body' => '',\n                'headers' => [\n                    'Cache-Control' => 's-maxage=0',\n                ],\n            ],\n        ]);\n\n        // Re-request with Last-Modified time that we received when the cache was primed\n        $this->request('GET', '/', ['HTTP_IF_MODIFIED_SINCE' => 'Mon, 12 Aug 2024 10:05:00 +0000'], [], true);\n\n        $this->assertSame(200, $this->response->getStatusCode());\n\n        // The cache should use the content (\"embedded\") from the cached entry\n        $this->assertSame('main embedded', $this->response->getContent());\n\n        $traces = $this->cache->getTraces();\n        $this->assertSame(['stale', 'invalid', 'store'], $traces['GET /']);\n\n        // Check that the embedded resource was successfully revalidated\n        $this->assertSame(['stale', 'valid', 'store'], $traces['GET /foo']);\n    }\n\n    public function testEsiCacheIncludesEmbeddedResponseContentWhenMainAndEmbeddedResponseAreFresh()\n    {\n        $this->setNextResponses([\n            [\n                'status' => 200,\n                'body' => 'main <esi:include src=\"/foo\" />',\n                'headers' => [\n                    'Cache-Control' => 's-maxage=10',\n                    'Surrogate-Control' => 'content=\"ESI/1.0\"',\n                    'Last-Modified' => 'Mon, 12 Aug 2024 10:05:00 +0000',\n                ],\n            ],\n            [\n                'status' => 200,\n                'body' => 'embedded',\n                'headers' => [\n                    'Cache-Control' => 's-maxage=10',\n                    'Last-Modified' => 'Mon, 12 Aug 2024 10:00:00 +0000',\n                ],\n            ],\n        ]);\n\n        // prime the cache\n        $this->request('GET', '/', [], [], true);\n        $this->assertSame(200, $this->response->getStatusCode());\n        $this->assertSame('main embedded', $this->response->getContent());\n        $this->assertSame('Mon, 12 Aug 2024 10:05:00 +0000', $this->response->getLastModified()->format(\\DATE_RFC2822));\n\n        // Assume that a client received 'Mon, 12 Aug 2024 10:00:00 +0000' as last-modified information in the past. This may, for example,\n        // be the case when the \"main\" response at that point had an older Last-Modified time, so the embedded response's Last-Modified time\n        // governed the result for the combined response. In other words, the client received a Last-Modified time that still validates the\n        // embedded response as of now, but no longer matches the Last-Modified time of the \"main\" resource.\n        // Now this client does a revalidation request.\n        $this->request('GET', '/', ['HTTP_IF_MODIFIED_SINCE' => 'Mon, 12 Aug 2024 10:00:00 +0000'], [], true);\n\n        $this->assertSame(200, $this->response->getStatusCode());\n\n        // The cache should use the content (\"embedded\") from the cached entry\n        $this->assertSame('main embedded', $this->response->getContent());\n\n        $traces = $this->cache->getTraces();\n        $this->assertSame(['fresh'], $traces['GET /']);\n\n        // Check that the embedded resource was successfully revalidated\n        $this->assertSame(['fresh'], $traces['GET /foo']);\n    }\n\n    public function testEsiCacheForceValidation()\n    {\n        $responses = [\n            [\n                'status' => 200,\n                'body' => '<esi:include src=\"/foo\" /> <esi:include src=\"/bar\" />',\n                'headers' => [\n                    'Cache-Control' => 's-maxage=300',\n                    'Surrogate-Control' => 'content=\"ESI/1.0\"',\n                ],\n            ],\n            [\n                'status' => 200,\n                'body' => 'Hello World!',\n                'headers' => ['ETag' => 'foobar'],\n            ],\n            [\n                'status' => 200,\n                'body' => 'My name is Bobby.',\n                'headers' => ['Cache-Control' => 's-maxage=100'],\n            ],\n        ];\n\n        $this->setNextResponses($responses);\n\n        $this->request('GET', '/', [], [], true);\n        $this->assertEquals('Hello World! My name is Bobby.', $this->response->getContent());\n        $this->assertNull($this->response->getTtl());\n        $this->assertTrue($this->response->headers->hasCacheControlDirective('private'));\n        $this->assertTrue($this->response->headers->hasCacheControlDirective('no-cache'));\n    }\n\n    public function testEsiCacheForceValidationForHeadRequests()\n    {\n        $responses = [\n            [\n                'status' => 200,\n                'body' => 'I am the main response and use expiration caching, but I embed another resource: <esi:include src=\"/foo\" />',\n                'headers' => [\n                    'Cache-Control' => 's-maxage=300',\n                    'Surrogate-Control' => 'content=\"ESI/1.0\"',\n                ],\n            ],\n            [\n                'status' => 200,\n                'body' => 'I am the embedded resource and use validation caching',\n                'headers' => ['ETag' => 'foobar'],\n            ],\n        ];\n\n        $this->setNextResponses($responses);\n\n        $this->request('HEAD', '/', [], [], true);\n\n        // The response has been assembled from expiration and validation based resources\n        // This can neither be cached nor revalidated, so it should be private/no cache\n        $this->assertSame('', $this->response->getContent());\n        $this->assertNull($this->response->getTtl());\n        $this->assertTrue($this->response->headers->hasCacheControlDirective('private'));\n        $this->assertTrue($this->response->headers->hasCacheControlDirective('no-cache'));\n    }\n\n    public function testEsiRecalculateContentLengthHeader()\n    {\n        $responses = [\n            [\n                'status' => 200,\n                'body' => '<esi:include src=\"/foo\" />',\n                'headers' => [\n                    'Content-Length' => 26,\n                    'Surrogate-Control' => 'content=\"ESI/1.0\"',\n                ],\n            ],\n            [\n                'status' => 200,\n                'body' => 'Hello World!',\n                'headers' => [],\n            ],\n        ];\n\n        $this->setNextResponses($responses);\n\n        $this->request('GET', '/', [], [], true);\n        $this->assertEquals('Hello World!', $this->response->getContent());\n        $this->assertEquals(12, $this->response->headers->get('Content-Length'));\n    }\n\n    public function testEsiRecalculateContentLengthHeaderForHeadRequest()\n    {\n        $responses = [\n            [\n                'status' => 200,\n                'body' => '<esi:include src=\"/foo\" />',\n                'headers' => [\n                    'Content-Length' => 26,\n                    'Surrogate-Control' => 'content=\"ESI/1.0\"',\n                ],\n            ],\n            [\n                'status' => 200,\n                'body' => 'Hello World!',\n                'headers' => [],\n            ],\n        ];\n\n        $this->setNextResponses($responses);\n\n        $this->request('HEAD', '/', [], [], true);\n\n        // https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13\n        // \"The Content-Length entity-header field indicates the size of the entity-body,\n        // in decimal number of OCTETs, sent to the recipient or, in the case of the HEAD\n        // method, the size of the entity-body that would have been sent had the request\n        // been a GET.\"\n        $this->assertSame('', $this->response->getContent());\n        $this->assertEquals(12, $this->response->headers->get('Content-Length'));\n    }\n\n    public function testClientIpIsAlwaysLocalhostForForwardedRequests()\n    {\n        $this->setNextResponse();\n        $this->request('GET', '/', ['REMOTE_ADDR' => '10.0.0.1']);\n\n        $this->kernel->assert(function ($backendRequest) {\n            $this->assertSame('127.0.0.1', $backendRequest->server->get('REMOTE_ADDR'));\n        });\n    }\n\n    #[DataProvider('getTrustedProxyData')]\n    public function testHttpCacheIsSetAsATrustedProxy(array $existing)\n    {\n        Request::setTrustedProxies($existing, Request::HEADER_X_FORWARDED_FOR);\n\n        $this->setNextResponse();\n        $this->request('GET', '/', ['REMOTE_ADDR' => '10.0.0.1']);\n        $this->assertSame($existing, Request::getTrustedProxies());\n\n        $existing = array_unique(array_merge($existing, ['127.0.0.1']));\n        $this->kernel->assert(function ($backendRequest) use ($existing) {\n            $this->assertSame($existing, Request::getTrustedProxies());\n            $this->assertsame('10.0.0.1', $backendRequest->getClientIp());\n        });\n\n        Request::setTrustedProxies([], -1);\n    }\n\n    public static function getTrustedProxyData()\n    {\n        return [\n            [[]],\n            [['10.0.0.2']],\n            [['10.0.0.2', '127.0.0.1']],\n        ];\n    }\n\n    #[DataProvider('getForwardedData')]\n    public function testForwarderHeaderForForwardedRequests($forwarded, $expected)\n    {\n        $this->setNextResponse();\n        $server = ['REMOTE_ADDR' => '10.0.0.1'];\n        if (null !== $forwarded) {\n            Request::setTrustedProxies($server, -1);\n            $server['HTTP_FORWARDED'] = $forwarded;\n        }\n        $this->request('GET', '/', $server);\n\n        $this->kernel->assert(function ($backendRequest) use ($expected) {\n            $this->assertSame($expected, $backendRequest->headers->get('Forwarded'));\n        });\n\n        Request::setTrustedProxies([], -1);\n    }\n\n    public static function getForwardedData()\n    {\n        return [\n            [null, 'for=\"10.0.0.1\";host=\"localhost\";proto=http'],\n            ['for=10.0.0.2', 'for=\"10.0.0.2\";host=\"localhost\";proto=http, for=\"10.0.0.1\"'],\n            ['for=10.0.0.2, for=10.0.0.3', 'for=\"10.0.0.2\";host=\"localhost\";proto=http, for=\"10.0.0.3\", for=\"10.0.0.1\"'],\n        ];\n    }\n\n    public function testEsiCacheRemoveValidationHeadersIfEmbeddedResponses()\n    {\n        $time = \\DateTimeImmutable::createFromFormat('U', time());\n\n        $responses = [\n            [\n                'status' => 200,\n                'body' => '<esi:include src=\"/hey\" />',\n                'headers' => [\n                    'Surrogate-Control' => 'content=\"ESI/1.0\"',\n                    'ETag' => 'hey',\n                    'Last-Modified' => $time->format(\\DATE_RFC2822),\n                ],\n            ],\n            [\n                'status' => 200,\n                'body' => 'Hey!',\n                'headers' => [],\n            ],\n        ];\n\n        $this->setNextResponses($responses);\n\n        $this->request('GET', '/', [], [], true);\n        $this->assertNull($this->response->getETag());\n        $this->assertNull($this->response->getLastModified());\n    }\n\n    public function testEsiCacheRemoveValidationHeadersIfEmbeddedResponsesAndHeadRequest()\n    {\n        $time = \\DateTimeImmutable::createFromFormat('U', time());\n\n        $responses = [\n            [\n                'status' => 200,\n                'body' => '<esi:include src=\"/hey\" />',\n                'headers' => [\n                    'Surrogate-Control' => 'content=\"ESI/1.0\"',\n                    'ETag' => 'hey',\n                    'Last-Modified' => $time->format(\\DATE_RFC2822),\n                ],\n            ],\n            [\n                'status' => 200,\n                'body' => 'Hey!',\n                'headers' => [],\n            ],\n        ];\n\n        $this->setNextResponses($responses);\n\n        $this->request('HEAD', '/', [], [], true);\n        $this->assertSame('', $this->response->getContent());\n        $this->assertNull($this->response->getETag());\n        $this->assertNull($this->response->getLastModified());\n    }\n\n    public function testDoesNotCacheOptionsRequest()\n    {\n        $this->setNextResponse(200, ['Cache-Control' => 'public, s-maxage=60'], 'get');\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsCalled();\n\n        $this->setNextResponse(200, ['Cache-Control' => 'public, s-maxage=60'], 'options');\n        $this->request('OPTIONS', '/');\n        $this->assertHttpKernelIsCalled();\n\n        $this->request('GET', '/');\n        $this->assertHttpKernelIsNotCalled();\n        $this->assertSame('get', $this->response->getContent());\n    }\n\n    public function testUsesOriginalRequestForSurrogate()\n    {\n        $kernel = $this->createMock(HttpKernelInterface::class);\n        $store = $this->createStub(StoreInterface::class);\n\n        $kernel\n            ->expects($this->exactly(2))\n            ->method('handle')\n            ->willReturnCallback(function (Request $request) {\n                $this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR'));\n\n                return new Response();\n            });\n\n        $cache = new HttpCache($kernel,\n            $store,\n            new Esi()\n        );\n\n        $request = Request::create('/');\n        $request->server->set('REMOTE_ADDR', '10.0.0.1');\n\n        // Main request\n        $cache->handle($request, HttpKernelInterface::MAIN_REQUEST);\n\n        // Main request was now modified by HttpCache\n        // The surrogate will ask for the request using $this->cache->getRequest()\n        // which MUST return the original request so the surrogate\n        // can actually behave like a reverse proxy like e.g. Varnish would.\n        $this->assertSame('10.0.0.1', $cache->getRequest()->getClientIp());\n        $this->assertSame('10.0.0.1', $cache->getRequest()->server->get('REMOTE_ADDR'));\n\n        // Surrogate request\n        $cache->handle($request, HttpKernelInterface::SUB_REQUEST);\n    }\n\n    public function testStaleIfErrorMustNotResetLifetime()\n    {\n        // Make sure we don't accidentally treat the response as fresh (revalidated) again\n        // when stale-if-error handling kicks in.\n\n        $responses = [\n            [\n                'status' => 200,\n                'body' => 'OK',\n                // This is cacheable and can be used in stale-if-error cases:\n                'headers' => ['Cache-Control' => 'public, max-age=10', 'ETag' => 'some-etag'],\n            ],\n            [\n                'status' => 500,\n                'body' => 'FAIL',\n                'headers' => [],\n            ],\n            [\n                'status' => 500,\n                'body' => 'FAIL',\n                'headers' => [],\n            ],\n        ];\n\n        $this->setNextResponses($responses);\n        $this->cacheConfig['stale_if_error'] = 10;\n\n        $this->request('GET', '/'); // warm cache\n\n        sleep(15); // now the entry is stale, but still within the grace period (10s max-age + 10s stale-if-error)\n\n        $this->request('GET', '/'); // hit backend error\n        $this->assertEquals(200, $this->response->getStatusCode()); // stale-if-error saved the day\n        $this->assertEquals(15, $this->response->getAge());\n\n        sleep(10); // now we're outside the grace period\n\n        $this->request('GET', '/'); // hit backend error\n        $this->assertEquals(500, $this->response->getStatusCode()); // fail\n    }\n\n    #[DataProvider('getResponseDataThatMayBeServedStaleIfError')]\n    public function testResponsesThatMayBeUsedStaleIfError($responseHeaders, $sleepBetweenRequests = null)\n    {\n        $responses = [\n            [\n                'status' => 200,\n                'body' => 'OK',\n                'headers' => $responseHeaders,\n            ],\n            [\n                'status' => 500,\n                'body' => 'FAIL',\n                'headers' => [],\n            ],\n        ];\n\n        $this->setNextResponses($responses);\n        $this->cacheConfig['stale_if_error'] = 10; // after stale, may be served for 10s\n\n        $this->request('GET', '/'); // warm cache\n\n        if ($sleepBetweenRequests) {\n            sleep($sleepBetweenRequests);\n        }\n\n        $this->request('GET', '/'); // hit backend error\n\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('OK', $this->response->getContent());\n        $this->assertTraceContains('stale-if-error');\n    }\n\n    public static function getResponseDataThatMayBeServedStaleIfError()\n    {\n        // All data sets assume that a 10s stale-if-error grace period has been configured\n        yield 'public, max-age expired' => [['Cache-Control' => 'public, max-age=60'], 65];\n        yield 'public, validateable with ETag, no TTL' => [['Cache-Control' => 'public', 'ETag' => 'some-etag'], 5];\n        yield 'public, validateable with Last-Modified, no TTL' => [['Cache-Control' => 'public', 'Last-Modified' => 'yesterday'], 5];\n        yield 'public, s-maxage will be served stale-if-error, even if the RFC mandates otherwise' => [['Cache-Control' => 'public, s-maxage=20'], 25];\n    }\n\n    #[DataProvider('getResponseDataThatMustNotBeServedStaleIfError')]\n    public function testResponsesThatMustNotBeUsedStaleIfError($responseHeaders, $sleepBetweenRequests = null)\n    {\n        $responses = [\n            [\n                'status' => 200,\n                'body' => 'OK',\n                'headers' => $responseHeaders,\n            ],\n            [\n                'status' => 500,\n                'body' => 'FAIL',\n                'headers' => [],\n            ],\n        ];\n\n        $this->setNextResponses($responses);\n        $this->cacheConfig['stale_if_error'] = 10; // after stale, may be served for 10s\n        $this->cacheConfig['strict_smaxage'] = true; // full RFC compliance for this feature\n\n        $this->request('GET', '/'); // warm cache\n\n        if ($sleepBetweenRequests) {\n            sleep($sleepBetweenRequests);\n        }\n\n        $this->request('GET', '/'); // hit backend error\n\n        $this->assertEquals(500, $this->response->getStatusCode());\n    }\n\n    public function testSkipsConfiguredResponseHeadersForStore()\n    {\n        $storeMock = $this->createMock(StoreInterface::class);\n        $storeMock\n            ->expects($this->once())\n            ->method('write')\n            ->with(\n                $this->isInstanceOf(Request::class),\n                $this->callback(function (Response $response) {\n                    $this->assertFalse($response->headers->has('Set-Cookie'));\n                    $this->assertFalse($response->headers->has('Another-One-To-Skip'));\n                    $this->assertTrue($response->headers->has('Cache-Control'));\n                    $this->assertTrue($response->headers->has('Another-One-To-Keep'));\n\n                    return true;\n                })\n            );\n\n        $this->setNextResponse(200, [\n            'Cache-Control' => 'public, s-maxage=20',\n            'Set-Cookie' => 'foobar=value; path=/',\n            'Another-One-To-Skip' => 'foobar',\n            'Another-One-To-Keep' => 'foobar',\n        ]);\n\n        $httpCache = new HttpCache($this->kernel, $storeMock, null, [\n            'skip_response_headers' => ['Set-Cookie', 'Another-One-To-Skip', 'I-do-Not-Exist'],\n        ]);\n\n        $response = $httpCache->handle(Request::create('/'));\n\n        $this->assertSame('foobar=value; path=/', $response->headers->get('Set-Cookie'));\n        $this->assertSame('foobar', $response->headers->get('Another-One-To-Skip'));\n        $this->assertSame('foobar', $response->headers->get('Another-One-To-Keep'));\n        $this->assertFalse($response->headers->has('I-do-Not-Exist'));\n    }\n\n    public static function getResponseDataThatMustNotBeServedStaleIfError()\n    {\n        // All data sets assume that a 10s stale-if-error grace period has been configured\n        yield 'public, no TTL but beyond grace period' => [['Cache-Control' => 'public'], 15];\n        yield 'public, validateable with ETag, no TTL but beyond grace period' => [['Cache-Control' => 'public', 'ETag' => 'some-etag'], 15];\n        yield 'public, validateable with Last-Modified, no TTL but beyond grace period' => [['Cache-Control' => 'public', 'Last-Modified' => 'yesterday'], 15];\n        yield 'public, stale beyond grace period' => [['Cache-Control' => 'public, max-age=10'], 30];\n\n        // Cache-control values that prohibit serving stale responses or responses without positive validation -\n        // see https://tools.ietf.org/html/rfc7234#section-4.2.4 and\n        // https://tools.ietf.org/html/rfc7234#section-5.2.2\n        yield 'no-cache requires positive validation' => [['Cache-Control' => 'public, no-cache', 'ETag' => 'some-etag']];\n        yield 'no-cache requires positive validation, even if fresh' => [['Cache-Control' => 'public, no-cache, max-age=10']];\n        yield 'must-revalidate requires positive validation once stale' => [['Cache-Control' => 'public, max-age=10, must-revalidate'], 15];\n        yield 'proxy-revalidate requires positive validation once stale' => [['Cache-Control' => 'public, max-age=10, proxy-revalidate'], 15];\n    }\n\n    public function testStaleIfErrorWhenStrictSmaxageDisabled()\n    {\n        $responses = [\n            [\n                'status' => 200,\n                'body' => 'OK',\n                'headers' => ['Cache-Control' => 'public, s-maxage=20'],\n            ],\n            [\n                'status' => 500,\n                'body' => 'FAIL',\n                'headers' => [],\n            ],\n        ];\n\n        $this->setNextResponses($responses);\n        $this->cacheConfig['stale_if_error'] = 10;\n        $this->cacheConfig['strict_smaxage'] = false;\n\n        $this->request('GET', '/'); // warm cache\n        sleep(25);\n        $this->request('GET', '/'); // hit backend error\n\n        $this->assertEquals(200, $this->response->getStatusCode());\n        $this->assertEquals('OK', $this->response->getContent());\n        $this->assertTraceContains('stale-if-error');\n    }\n\n    public function testTraceHeaderNameCanBeChanged()\n    {\n        $this->cacheConfig['trace_header'] = 'X-My-Header';\n        $this->setNextResponse();\n        $this->request('GET', '/');\n\n        $this->assertTrue($this->response->headers->has('X-My-Header'));\n    }\n\n    public function testTraceLevelDefaultsToFullIfDebug()\n    {\n        $this->setNextResponse();\n        $this->request('GET', '/');\n\n        $this->assertTrue($this->response->headers->has('X-Symfony-Cache'));\n        $this->assertEquals('GET /: miss', $this->response->headers->get('X-Symfony-Cache'));\n    }\n\n    public function testTraceLevelDefaultsToNoneIfNotDebug()\n    {\n        $this->cacheConfig['debug'] = false;\n        $this->setNextResponse();\n        $this->request('GET', '/');\n\n        $this->assertFalse($this->response->headers->has('X-Symfony-Cache'));\n    }\n\n    public function testTraceLevelShort()\n    {\n        $this->cacheConfig['trace_level'] = 'short';\n\n        $this->setNextResponse();\n        $this->request('GET', '/');\n\n        $this->assertTrue($this->response->headers->has('X-Symfony-Cache'));\n        $this->assertEquals('miss', $this->response->headers->get('X-Symfony-Cache'));\n    }\n\n    public function testQueryMethodIsCacheable()\n    {\n        $this->setNextResponse(200, ['Cache-Control' => 'public, max-age=10000'], 'Query result', function (Request $request) {\n            $this->assertSame('QUERY', $request->getMethod());\n\n            return '{\"query\": \"users\"}' === $request->getContent();\n        });\n\n        $this->kernel->reset();\n        $this->store = $this->createStore();\n        $this->cacheConfig['debug'] = true;\n        $this->cache = new HttpCache($this->kernel, $this->store, null, $this->cacheConfig);\n\n        $request1 = Request::create('/', 'QUERY', [], [], [], [], '{\"query\": \"users\"}');\n        $this->response = $this->cache->handle($request1, HttpKernelInterface::MAIN_REQUEST, $this->catch);\n\n        $this->assertSame(200, $this->response->getStatusCode());\n        $this->assertTraceContains('miss');\n        $this->assertSame('Query result', $this->response->getContent());\n\n        $request2 = Request::create('/', 'QUERY', [], [], [], [], '{\"query\": \"users\"}');\n        $this->response = $this->cache->handle($request2, HttpKernelInterface::MAIN_REQUEST, $this->catch);\n\n        $this->assertSame(200, $this->response->getStatusCode());\n        $this->assertTrue($this->response->headers->has('Age'));\n        $this->assertSame('Query result', $this->response->getContent());\n    }\n\n    public function testQueryMethodDifferentBodiesCreateDifferentCacheEntries()\n    {\n        $this->setNextResponses([\n            [\n                'status' => 200,\n                'body' => 'Users result',\n                'headers' => ['Cache-Control' => 'public, max-age=10000'],\n            ],\n            [\n                'status' => 200,\n                'body' => 'Posts result',\n                'headers' => ['Cache-Control' => 'public, max-age=10000'],\n            ],\n        ]);\n\n        $this->store = $this->createStore();\n        $this->cacheConfig['debug'] = true;\n        $this->cache = new HttpCache($this->kernel, $this->store, null, $this->cacheConfig);\n\n        $request1 = Request::create('/', 'QUERY', [], [], [], [], '{\"query\": \"users\"}');\n        $this->response = $this->cache->handle($request1, HttpKernelInterface::MAIN_REQUEST, $this->catch);\n\n        $this->assertSame('Users result', $this->response->getContent());\n        $this->assertTraceContains('miss');\n\n        $request2 = Request::create('/', 'QUERY', [], [], [], [], '{\"query\": \"posts\"}');\n        $this->response = $this->cache->handle($request2, HttpKernelInterface::MAIN_REQUEST, $this->catch);\n\n        $this->assertSame('Posts result', $this->response->getContent());\n        $this->assertTraceContains('miss');\n\n        $request3 = Request::create('/', 'QUERY', [], [], [], [], '{\"query\": \"users\"}');\n        $this->response = $this->cache->handle($request3, HttpKernelInterface::MAIN_REQUEST, $this->catch);\n\n        $this->assertSame('Users result', $this->response->getContent());\n        $this->assertTrue($this->response->headers->has('Age'));\n    }\n\n    public function testQueryMethodWithEmptyBodyIsCacheable()\n    {\n        $this->setNextResponse(200, ['Cache-Control' => 'public, max-age=10000'], 'Empty query result');\n        $this->kernel->reset();\n        $this->store = $this->createStore();\n        $this->cacheConfig['debug'] = true;\n        $this->cache = new HttpCache($this->kernel, $this->store, null, $this->cacheConfig);\n\n        $request1 = Request::create('/', 'QUERY', [], [], [], [], '');\n        $this->response = $this->cache->handle($request1, HttpKernelInterface::MAIN_REQUEST, $this->catch);\n\n        $this->assertSame(200, $this->response->getStatusCode());\n        $this->assertTraceContains('miss');\n\n        $request2 = Request::create('/', 'QUERY', [], [], [], [], '');\n        $this->response = $this->cache->handle($request2, HttpKernelInterface::MAIN_REQUEST, $this->catch);\n\n        $this->assertSame(200, $this->response->getStatusCode());\n        $this->assertTrue($this->response->headers->has('Age'));\n    }\n}\n\nclass TestKernel implements HttpKernelInterface\n{\n    public bool $terminateCalled = false;\n\n    public function terminate(Request $request, Response $response)\n    {\n        $this->terminateCalled = true;\n    }\n\n    public function handle(Request $request, $type = self::MAIN_REQUEST, $catch = true): Response\n    {\n    }\n}\n"
  },
  {
    "path": "Tests/HttpCache/HttpCacheTestCase.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\HttpCache;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\EventDispatcher\\EventDispatcher;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\Esi;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\Store;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\n\nabstract class HttpCacheTestCase extends TestCase\n{\n    protected $kernel;\n    protected $cache;\n    protected $caches;\n    protected $cacheConfig;\n    protected $request;\n    protected $response;\n    protected $responses;\n    protected $catch;\n    protected $esi;\n    protected ?Store $store = null;\n\n    protected function setUp(): void\n    {\n        $this->kernel = null;\n\n        $this->cache = null;\n        $this->esi = null;\n        $this->caches = [];\n        $this->cacheConfig = [];\n\n        $this->request = null;\n        $this->response = null;\n        $this->responses = [];\n\n        $this->catch = false;\n\n        $this->clearDirectory(sys_get_temp_dir().'/http_cache');\n    }\n\n    protected function tearDown(): void\n    {\n        $this->cache?->getStore()->cleanup();\n        $this->kernel = null;\n        $this->cache = null;\n        $this->caches = null;\n        $this->request = null;\n        $this->response = null;\n        $this->responses = null;\n        $this->cacheConfig = null;\n        $this->catch = null;\n        $this->esi = null;\n\n        $this->clearDirectory(sys_get_temp_dir().'/http_cache');\n    }\n\n    public function assertHttpKernelIsCalled()\n    {\n        $this->assertTrue($this->kernel->hasBeenCalled());\n    }\n\n    public function assertHttpKernelIsNotCalled()\n    {\n        $this->assertFalse($this->kernel->hasBeenCalled());\n    }\n\n    public function assertResponseOk()\n    {\n        $this->assertEquals(200, $this->response->getStatusCode());\n    }\n\n    public function assertTraceContains($trace)\n    {\n        $traces = $this->cache->getTraces();\n        $traces = current($traces);\n\n        $this->assertMatchesRegularExpression('/'.$trace.'/', implode(', ', $traces));\n    }\n\n    public function assertTraceNotContains($trace)\n    {\n        $traces = $this->cache->getTraces();\n        $traces = current($traces);\n\n        $this->assertDoesNotMatchRegularExpression('/'.$trace.'/', implode(', ', $traces));\n    }\n\n    public function assertExceptionsAreCaught()\n    {\n        $this->assertTrue($this->kernel->isCatchingExceptions());\n    }\n\n    public function assertExceptionsAreNotCaught()\n    {\n        $this->assertFalse($this->kernel->isCatchingExceptions());\n    }\n\n    public function request($method, $uri = '/', $server = [], $cookies = [], $esi = false, $headers = [])\n    {\n        if (null === $this->kernel) {\n            throw new \\LogicException('You must call setNextResponse() before calling request().');\n        }\n\n        $this->kernel->reset();\n\n        if (!$this->store) {\n            $this->store = $this->createStore();\n        }\n\n        if (!isset($this->cacheConfig['debug'])) {\n            $this->cacheConfig['debug'] = true;\n        }\n\n        $this->esi = $esi ? new Esi() : null;\n        $this->cache = new HttpCache($this->kernel, $this->store, $this->esi, $this->cacheConfig);\n        $this->request = Request::create($uri, $method, [], $cookies, [], $server);\n        $this->request->headers->add($headers);\n\n        $this->response = $this->cache->handle($this->request, HttpKernelInterface::MAIN_REQUEST, $this->catch);\n\n        $this->responses[] = $this->response;\n    }\n\n    public function getMetaStorageValues()\n    {\n        $values = [];\n        foreach (new \\RecursiveIteratorIterator(new \\RecursiveDirectoryIterator(sys_get_temp_dir().'/http_cache/md', \\RecursiveDirectoryIterator::SKIP_DOTS), \\RecursiveIteratorIterator::LEAVES_ONLY) as $file) {\n            $values[] = file_get_contents($file);\n        }\n\n        return $values;\n    }\n\n    // A basic response with 200 status code and a tiny body.\n    public function setNextResponse($statusCode = 200, array $headers = [], $body = 'Hello World', ?\\Closure $customizer = null, ?EventDispatcher $eventDispatcher = null)\n    {\n        $this->kernel = new TestHttpKernel($body, $statusCode, $headers, $customizer, $eventDispatcher);\n    }\n\n    public function setNextResponses($responses)\n    {\n        $this->kernel = new TestMultipleHttpKernel($responses);\n    }\n\n    public function catchExceptions($catch = true)\n    {\n        $this->catch = $catch;\n    }\n\n    public static function clearDirectory($directory)\n    {\n        if (!is_dir($directory)) {\n            return;\n        }\n\n        $fp = opendir($directory);\n        while (false !== $file = readdir($fp)) {\n            if (!\\in_array($file, ['.', '..'], true)) {\n                if (is_link($directory.'/'.$file)) {\n                    unlink($directory.'/'.$file);\n                } elseif (is_dir($directory.'/'.$file)) {\n                    self::clearDirectory($directory.'/'.$file);\n                    rmdir($directory.'/'.$file);\n                } else {\n                    unlink($directory.'/'.$file);\n                }\n            }\n        }\n\n        closedir($fp);\n    }\n\n    protected function createStore(): Store\n    {\n        return new Store(sys_get_temp_dir().'/http_cache');\n    }\n}\n"
  },
  {
    "path": "Tests/HttpCache/ResponseCacheStrategyTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\HttpCache;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\Attributes\\Group;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\ResponseCacheStrategy;\n\nclass ResponseCacheStrategyTest extends TestCase\n{\n    public function testMinimumSharedMaxAgeWins()\n    {\n        $cacheStrategy = new ResponseCacheStrategy();\n\n        $response1 = new Response();\n        $response1->setSharedMaxAge(60);\n        $cacheStrategy->add($response1);\n\n        $response2 = new Response();\n        $response2->setSharedMaxAge(3600);\n        $cacheStrategy->add($response2);\n\n        $response = new Response();\n        $response->setSharedMaxAge(86400);\n        $cacheStrategy->update($response);\n\n        $this->assertSame('60', $response->headers->getCacheControlDirective('s-maxage'));\n    }\n\n    public function testSharedMaxAgeNotSetIfNotSetInAnyEmbeddedRequest()\n    {\n        $cacheStrategy = new ResponseCacheStrategy();\n\n        $response1 = new Response();\n        $response1->setSharedMaxAge(60);\n        $cacheStrategy->add($response1);\n\n        $response2 = new Response();\n        $cacheStrategy->add($response2);\n\n        $response = new Response();\n        $response->setSharedMaxAge(86400);\n        $cacheStrategy->update($response);\n\n        $this->assertFalse($response->headers->hasCacheControlDirective('s-maxage'));\n    }\n\n    public function testSharedMaxAgeNotSetIfNotSetInMainRequest()\n    {\n        $cacheStrategy = new ResponseCacheStrategy();\n\n        $response1 = new Response();\n        $response1->setSharedMaxAge(60);\n        $cacheStrategy->add($response1);\n\n        $response2 = new Response();\n        $response2->setSharedMaxAge(3600);\n        $cacheStrategy->add($response2);\n\n        $response = new Response();\n        $cacheStrategy->update($response);\n\n        $this->assertFalse($response->headers->hasCacheControlDirective('s-maxage'));\n    }\n\n    public function testExpiresHeaderUpdatedFromMaxAge()\n    {\n        $cacheStrategy = new ResponseCacheStrategy();\n\n        $response1 = new Response();\n        $response1->setExpires(new \\DateTime('+ 1 hour'));\n        $response1->setPublic();\n        $cacheStrategy->add($response1);\n\n        $response = new Response();\n        $response->setMaxAge(0);\n        $response->setSharedMaxAge(86400);\n        $cacheStrategy->update($response);\n\n        $this->assertSame('0', $response->headers->getCacheControlDirective('max-age'));\n        $this->assertSame('3600', $response->headers->getCacheControlDirective('s-maxage'));\n\n        // Expires header must be same as Date header because \"max-age\" is 0.\n        $this->assertSame($response->headers->get('Date'), $response->headers->get('Expires'));\n    }\n\n    public function testMaxAgeUpdatedFromExpiresHeader()\n    {\n        $cacheStrategy = new ResponseCacheStrategy();\n\n        $response1 = new Response();\n        $response1->setExpires(new \\DateTime('+ 1 hour', new \\DateTimeZone('UTC')));\n        $response1->setPublic();\n        $cacheStrategy->add($response1);\n\n        $response = new Response();\n        $response->setMaxAge(86400);\n        $cacheStrategy->update($response);\n\n        $this->assertSame('3600', $response->headers->getCacheControlDirective('max-age'));\n        $this->assertNull($response->headers->getCacheControlDirective('s-maxage'));\n        $this->assertSame((new \\DateTime('+ 1 hour', new \\DateTimeZone('UTC')))->format('D, d M Y H:i:s').' GMT', $response->headers->get('Expires'));\n    }\n\n    public function testMaxAgeAndSharedMaxAgeUpdatedFromExpiresHeader()\n    {\n        $cacheStrategy = new ResponseCacheStrategy();\n\n        $response1 = new Response();\n        $response1->setExpires(new \\DateTime('+ 1 day', new \\DateTimeZone('UTC')));\n        $response1->setPublic();\n        $cacheStrategy->add($response1);\n\n        $response = new Response();\n        $response->setMaxAge(3600);\n        $response->setSharedMaxAge(86400);\n        $cacheStrategy->update($response);\n\n        $this->assertSame('3600', $response->headers->getCacheControlDirective('max-age'));\n        $this->assertSame('86400', $response->headers->getCacheControlDirective('s-maxage'));\n        $this->assertSame((new \\DateTime('+ 1 hour', new \\DateTimeZone('UTC')))->format('D, d M Y H:i:s').' GMT', $response->headers->get('Expires'));\n    }\n\n    public function testMainResponseNotCacheableWhenEmbeddedResponseRequiresValidation()\n    {\n        $cacheStrategy = new ResponseCacheStrategy();\n\n        $embeddedResponse = new Response();\n        $embeddedResponse->setLastModified(new \\DateTimeImmutable());\n        $cacheStrategy->add($embeddedResponse);\n\n        $mainResponse = new Response();\n        $mainResponse->setSharedMaxAge(3600);\n        $cacheStrategy->update($mainResponse);\n\n        $this->assertTrue($mainResponse->headers->hasCacheControlDirective('no-cache'));\n        $this->assertTrue($mainResponse->headers->hasCacheControlDirective('must-revalidate'));\n        $this->assertFalse($mainResponse->isFresh());\n    }\n\n    public function testValidationOnMainResponseIsNotPossibleWhenItContainsEmbeddedResponses()\n    {\n        $cacheStrategy = new ResponseCacheStrategy();\n\n        // This main response uses the \"validation\" model\n        $mainResponse = new Response();\n        $mainResponse->setLastModified(new \\DateTimeImmutable());\n        $mainResponse->setEtag('foo');\n\n        // Embedded response uses \"expiry\" model\n        $embeddedResponse = new Response();\n        $mainResponse->setSharedMaxAge(3600);\n        $cacheStrategy->add($embeddedResponse);\n\n        $cacheStrategy->update($mainResponse);\n\n        $this->assertFalse($mainResponse->isValidateable());\n        $this->assertFalse($mainResponse->headers->has('Last-Modified'));\n        $this->assertFalse($mainResponse->headers->has('ETag'));\n        $this->assertTrue($mainResponse->headers->hasCacheControlDirective('no-cache'));\n        $this->assertTrue($mainResponse->headers->hasCacheControlDirective('must-revalidate'));\n    }\n\n    public function testMainResponseWithValidationIsUnchangedWhenThereIsNoEmbeddedResponse()\n    {\n        $cacheStrategy = new ResponseCacheStrategy();\n\n        $mainResponse = new Response();\n        $mainResponse->setLastModified(new \\DateTimeImmutable());\n        $cacheStrategy->update($mainResponse);\n\n        $this->assertTrue($mainResponse->isValidateable());\n    }\n\n    public function testMainResponseWithExpirationIsUnchangedWhenThereIsNoEmbeddedResponse()\n    {\n        $cacheStrategy = new ResponseCacheStrategy();\n\n        $mainResponse = new Response();\n        $mainResponse->setSharedMaxAge(3600);\n        $cacheStrategy->update($mainResponse);\n\n        $this->assertTrue($mainResponse->isFresh());\n    }\n\n    public function testLastModifiedIsMergedWithEmbeddedResponse()\n    {\n        $cacheStrategy = new ResponseCacheStrategy();\n\n        $mainResponse = new Response();\n        $mainResponse->setLastModified(new \\DateTimeImmutable('-2 hour'));\n\n        $embeddedDate = new \\DateTimeImmutable('-1 hour');\n        $embeddedResponse = new Response();\n        $embeddedResponse->setLastModified($embeddedDate);\n\n        $cacheStrategy->add($embeddedResponse);\n        $cacheStrategy->update($mainResponse);\n\n        $this->assertTrue($mainResponse->headers->has('Last-Modified'));\n        $this->assertSame($embeddedDate->getTimestamp(), $mainResponse->getLastModified()->getTimestamp());\n    }\n\n    public function testLastModifiedIsRemovedWhenEmbeddedResponseHasNoLastModified()\n    {\n        $cacheStrategy = new ResponseCacheStrategy();\n\n        $mainResponse = new Response();\n        $mainResponse->setLastModified(new \\DateTimeImmutable('-2 hour'));\n\n        $embeddedResponse = new Response();\n\n        $cacheStrategy->add($embeddedResponse);\n        $cacheStrategy->update($mainResponse);\n\n        $this->assertFalse($mainResponse->headers->has('Last-Modified'));\n    }\n\n    public function testLastModifiedIsNotAddedWhenMainResponseHasNoLastModified()\n    {\n        $cacheStrategy = new ResponseCacheStrategy();\n\n        $mainResponse = new Response();\n\n        $embeddedResponse = new Response();\n        $embeddedResponse->setLastModified(new \\DateTimeImmutable('-2 hour'));\n\n        $cacheStrategy->add($embeddedResponse);\n        $cacheStrategy->update($mainResponse);\n\n        $this->assertFalse($mainResponse->headers->has('Last-Modified'));\n    }\n\n    public function testMainResponseIsNotCacheableWhenEmbeddedResponseIsNotCacheable()\n    {\n        $cacheStrategy = new ResponseCacheStrategy();\n\n        $mainResponse = new Response();\n        $mainResponse->setSharedMaxAge(3600); // Public, cacheable\n\n        /* This response has no validation or expiration information.\n           That makes it uncacheable, it is always stale.\n           (It does *not* make this private, though.) */\n        $embeddedResponse = new Response();\n        $this->assertFalse($embeddedResponse->isFresh()); // not fresh, as no lifetime is provided\n\n        $cacheStrategy->add($embeddedResponse);\n        $cacheStrategy->update($mainResponse);\n\n        $this->assertTrue($mainResponse->headers->hasCacheControlDirective('no-cache'));\n        $this->assertTrue($mainResponse->headers->hasCacheControlDirective('must-revalidate'));\n        $this->assertFalse($mainResponse->isFresh());\n    }\n\n    public function testEmbeddingPrivateResponseMakesMainResponsePrivate()\n    {\n        $cacheStrategy = new ResponseCacheStrategy();\n\n        $mainResponse = new Response();\n        $mainResponse->setSharedMaxAge(3600); // public, cacheable\n\n        // The embedded response might for example contain per-user data that remains valid for 60 seconds\n        $embeddedResponse = new Response();\n        $embeddedResponse->setPrivate();\n        $embeddedResponse->setMaxAge(60); // this would implicitly set \"private\" as well, but let's be explicit\n\n        $cacheStrategy->add($embeddedResponse);\n        $cacheStrategy->update($mainResponse);\n\n        $this->assertTrue($mainResponse->headers->hasCacheControlDirective('private'));\n        $this->assertFalse($mainResponse->headers->hasCacheControlDirective('public'));\n    }\n\n    public function testEmbeddingPublicResponseDoesNotMakeMainResponsePublic()\n    {\n        $cacheStrategy = new ResponseCacheStrategy();\n\n        $mainResponse = new Response();\n        $mainResponse->setPrivate(); // this is the default, but let's be explicit\n        $mainResponse->setMaxAge(100);\n\n        $embeddedResponse = new Response();\n        $embeddedResponse->setPublic();\n        $embeddedResponse->setSharedMaxAge(100);\n\n        $cacheStrategy->add($embeddedResponse);\n        $cacheStrategy->update($mainResponse);\n\n        $this->assertTrue($mainResponse->headers->hasCacheControlDirective('private'));\n        $this->assertFalse($mainResponse->headers->hasCacheControlDirective('public'));\n    }\n\n    public function testResponseIsExiprableWhenEmbeddedResponseCombinesExpiryAndValidation()\n    {\n        /* When \"expiration wins over validation\" (https://symfony.com/doc/current/http_cache/validation.html)\n         * and both the main and embedded response provide s-maxage, then the more restricting value of both\n         * should be fine, regardless of whether the embedded response can be validated later on or must be\n         * completely regenerated.\n         */\n        $cacheStrategy = new ResponseCacheStrategy();\n\n        $mainResponse = new Response();\n        $mainResponse->setSharedMaxAge(3600);\n\n        $embeddedResponse = new Response();\n        $embeddedResponse->setSharedMaxAge(60);\n        $embeddedResponse->setEtag('foo');\n\n        $cacheStrategy->add($embeddedResponse);\n        $cacheStrategy->update($mainResponse);\n\n        $this->assertEqualsWithDelta(60, (int) $mainResponse->headers->getCacheControlDirective('s-maxage'), 1);\n    }\n\n    public function testResponseIsExpirableButNotValidateableWhenMainResponseCombinesExpirationAndValidation()\n    {\n        $cacheStrategy = new ResponseCacheStrategy();\n\n        $mainResponse = new Response();\n        $mainResponse->setSharedMaxAge(3600);\n        $mainResponse->setEtag('foo');\n        $mainResponse->setLastModified(new \\DateTimeImmutable());\n\n        $embeddedResponse = new Response();\n        $embeddedResponse->setSharedMaxAge(60);\n\n        $cacheStrategy->add($embeddedResponse);\n        $cacheStrategy->update($mainResponse);\n\n        $this->assertSame('60', $mainResponse->headers->getCacheControlDirective('s-maxage'));\n        $this->assertFalse($mainResponse->isValidateable());\n    }\n\n    #[DataProvider('cacheControlMergingProvider')]\n    #[Group('time-sensitive')]\n    public function testCacheControlMerging(array $expects, array $main, array $surrogates)\n    {\n        $cacheStrategy = new ResponseCacheStrategy();\n        $buildResponse = static function ($config) {\n            $response = new Response();\n\n            foreach ($config as $key => $value) {\n                switch ($key) {\n                    case 'age':\n                        $response->headers->set('Age', $value);\n                        break;\n\n                    case 'expires':\n                        $expires = clone $response->getDate();\n                        $expires = $expires->modify('+'.$value.' seconds');\n                        $response->setExpires($expires);\n                        break;\n\n                    case 'max-age':\n                        $response->setMaxAge($value);\n                        break;\n\n                    case 's-maxage':\n                        $response->setSharedMaxAge($value);\n                        break;\n\n                    case 'private':\n                        $response->setPrivate();\n                        break;\n\n                    case 'public':\n                        $response->setPublic();\n                        break;\n\n                    default:\n                        $response->headers->addCacheControlDirective($key, $value);\n                }\n            }\n\n            return $response;\n        };\n\n        foreach ($surrogates as $config) {\n            $cacheStrategy->add($buildResponse($config));\n        }\n\n        $response = $buildResponse($main);\n        $cacheStrategy->update($response);\n\n        foreach ($expects as $key => $value) {\n            if ('expires' === $key) {\n                $this->assertSame($value, $response->getExpires()->format('U') - $response->getDate()->format('U'));\n            } elseif ('age' === $key) {\n                $this->assertSame($value, $response->getAge());\n            } elseif (true === $value) {\n                $this->assertTrue($response->headers->hasCacheControlDirective($key), \\sprintf('Cache-Control header must have \"%s\" flag', $key));\n            } elseif (false === $value) {\n                $this->assertFalse(\n                    $response->headers->hasCacheControlDirective($key),\n                    \\sprintf('Cache-Control header must NOT have \"%s\" flag', $key)\n                );\n            } else {\n                $this->assertSame($value, $response->headers->getCacheControlDirective($key), \\sprintf('Cache-Control flag \"%s\" should be \"%s\"', $key, $value));\n            }\n        }\n    }\n\n    public static function cacheControlMergingProvider()\n    {\n        yield 'result is public if all responses are public' => [\n            ['private' => false, 'public' => true],\n            ['public' => true],\n            [\n                ['public' => true],\n            ],\n        ];\n\n        yield 'result is private by default' => [\n            ['private' => true, 'public' => false],\n            ['public' => true],\n            [\n                [],\n            ],\n        ];\n\n        yield 'combines public and private responses' => [\n            ['must-revalidate' => false, 'private' => true, 'public' => false],\n            ['public' => true],\n            [\n                ['private' => true],\n            ],\n        ];\n\n        yield 'inherits no-cache from surrogates' => [\n            ['no-cache' => true, 'public' => false],\n            ['public' => true],\n            [\n                ['no-cache' => true],\n            ],\n        ];\n\n        yield 'inherits no-store from surrogate' => [\n            ['no-store' => true, 'public' => false],\n            ['public' => true],\n            [\n                ['no-store' => true],\n            ],\n        ];\n\n        yield 'resolve to lowest possible max-age' => [\n            ['public' => false, 'private' => true, 's-maxage' => false, 'max-age' => '60'],\n            ['public' => true, 'max-age' => 3600],\n            [\n                ['private' => true, 'max-age' => 60],\n            ],\n        ];\n\n        yield 'resolves multiple max-age' => [\n            ['public' => false, 'private' => true, 's-maxage' => false, 'max-age' => '60'],\n            ['private' => true, 'max-age' => 100],\n            [\n                ['private' => true, 'max-age' => 3600],\n                ['public' => true, 'max-age' => 60, 's-maxage' => 60],\n                ['private' => true, 'max-age' => 60],\n            ],\n        ];\n\n        yield 'merge max-age and s-maxage' => [\n            ['public' => true, 'max-age' => null, 's-maxage' => '60'],\n            ['public' => true, 's-maxage' => 3600],\n            [\n                ['public' => true, 'max-age' => 60],\n            ],\n        ];\n\n        yield 's-maxage may be set to 0' => [\n            ['public' => true, 's-maxage' => '0', 'max-age' => null],\n            ['public' => true, 's-maxage' => '0'],\n            [\n                ['public' => true, 's-maxage' => '60'],\n            ],\n        ];\n\n        yield 's-maxage may be set to 0, and works independently from maxage' => [\n            ['public' => true, 's-maxage' => '0', 'max-age' => '30'],\n            ['public' => true, 's-maxage' => '0', 'max-age' => '30'],\n            [\n                ['public' => true, 'max-age' => '60'],\n            ],\n        ];\n\n        yield 'public subresponse without lifetime does not remove lifetime for main response' => [\n            ['public' => true, 's-maxage' => '30', 'max-age' => null],\n            ['public' => true, 's-maxage' => '30'],\n            [\n                ['public' => true],\n            ],\n        ];\n\n        yield 'lifetime for subresponse is kept when main response has no lifetime' => [\n            ['public' => true, 'max-age' => '30'],\n            ['public' => true],\n            [\n                ['public' => true, 'max-age' => '30'],\n            ],\n        ];\n\n        yield 's-maxage on the subresponse implies public, so the result is public as well' => [\n            ['public' => true, 'max-age' => '10', 's-maxage' => null],\n            ['public' => true, 'max-age' => '10'],\n            [\n                ['max-age' => '30', 's-maxage' => '20'],\n            ],\n        ];\n\n        yield 'result is private when combining private responses' => [\n            ['no-cache' => false, 'must-revalidate' => false, 'private' => true],\n            ['s-maxage' => 60, 'private' => true],\n            [\n                ['s-maxage' => 60, 'private' => true],\n            ],\n        ];\n\n        yield 'result can have s-maxage and max-age' => [\n            ['public' => true, 'private' => false, 's-maxage' => '60', 'max-age' => '30'],\n            ['s-maxage' => 100, 'max-age' => 2000],\n            [\n                ['s-maxage' => 1000, 'max-age' => 30],\n                ['s-maxage' => 500, 'max-age' => 500],\n                ['s-maxage' => 60, 'max-age' => 1000],\n            ],\n        ];\n\n        yield 'does not set headers without value' => [\n            ['max-age' => null, 's-maxage' => null, 'public' => null],\n            ['private' => true],\n            [\n                ['private' => true],\n            ],\n        ];\n\n        yield 'max-age 0 is sent to the client' => [\n            ['private' => true, 'max-age' => '0'],\n            ['max-age' => 0, 'private' => true],\n            [\n                ['max-age' => 60, 'private' => true],\n            ],\n        ];\n\n        yield 'max-age is relative to age' => [\n            ['max-age' => '240', 'age' => 60],\n            ['max-age' => 180],\n            [\n                ['max-age' => 600, 'age' => 60],\n            ],\n        ];\n\n        yield 'retains lowest age of all responses' => [\n            ['max-age' => '160', 'age' => 60],\n            ['max-age' => 600, 'age' => 60],\n            [\n                ['max-age' => 120, 'age' => 20],\n            ],\n        ];\n\n        yield 'max-age can be less than age, essentially expiring the response' => [\n            ['age' => 120, 'max-age' => '90'],\n            ['max-age' => 90, 'age' => 120],\n            [\n                ['max-age' => 120, 'age' => 60],\n            ],\n        ];\n\n        yield 'max-age is 0 regardless of age' => [\n            ['max-age' => '0'],\n            ['max-age' => 60],\n            [\n                ['max-age' => 0, 'age' => 60],\n            ],\n        ];\n\n        yield 'max-age is not negative' => [\n            ['max-age' => '0'],\n            ['max-age' => 0],\n            [\n                ['max-age' => 0, 'age' => 60],\n            ],\n        ];\n\n        yield 'calculates lowest Expires header' => [\n            ['expires' => 60],\n            ['expires' => 60],\n            [\n                ['expires' => 120],\n            ],\n        ];\n\n        yield 'calculates Expires header relative to age' => [\n            ['expires' => 210, 'age' => 120],\n            ['expires' => 90],\n            [\n                ['expires' => 600, 'age' => '120'],\n            ],\n        ];\n    }\n}\n"
  },
  {
    "path": "Tests/HttpCache/SsiTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\HttpCache;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\Ssi;\n\nclass SsiTest extends TestCase\n{\n    public function testHasSurrogateSsiCapability()\n    {\n        $ssi = new Ssi();\n\n        $request = Request::create('/');\n        $request->headers->set('Surrogate-Capability', 'abc=\"SSI/1.0\"');\n        $this->assertTrue($ssi->hasSurrogateCapability($request));\n\n        $request = Request::create('/');\n        $request->headers->set('Surrogate-Capability', 'foobar');\n        $this->assertFalse($ssi->hasSurrogateCapability($request));\n\n        $request = Request::create('/');\n        $this->assertFalse($ssi->hasSurrogateCapability($request));\n    }\n\n    public function testAddSurrogateSsiCapability()\n    {\n        $ssi = new Ssi();\n\n        $request = Request::create('/');\n        $ssi->addSurrogateCapability($request);\n        $this->assertEquals('symfony=\"SSI/1.0\"', $request->headers->get('Surrogate-Capability'));\n\n        $ssi->addSurrogateCapability($request);\n        $this->assertEquals('symfony=\"SSI/1.0\", symfony=\"SSI/1.0\"', $request->headers->get('Surrogate-Capability'));\n    }\n\n    public function testAddSurrogateControl()\n    {\n        $ssi = new Ssi();\n\n        $response = new Response('foo <!--#include virtual=\"\" -->');\n        $ssi->addSurrogateControl($response);\n        $this->assertEquals('content=\"SSI/1.0\"', $response->headers->get('Surrogate-Control'));\n\n        $response = new Response('foo');\n        $ssi->addSurrogateControl($response);\n        $this->assertEquals('', $response->headers->get('Surrogate-Control'));\n    }\n\n    public function testNeedsSsiParsing()\n    {\n        $ssi = new Ssi();\n\n        $response = new Response();\n        $response->headers->set('Surrogate-Control', 'content=\"SSI/1.0\"');\n        $this->assertTrue($ssi->needsParsing($response));\n\n        $response = new Response();\n        $this->assertFalse($ssi->needsParsing($response));\n    }\n\n    public function testRenderIncludeTag()\n    {\n        $ssi = new Ssi();\n\n        $this->assertEquals('<!--#include virtual=\"/\" -->', $ssi->renderIncludeTag('/', '/alt', true));\n        $this->assertEquals('<!--#include virtual=\"/\" -->', $ssi->renderIncludeTag('/', '/alt', false));\n        $this->assertEquals('<!--#include virtual=\"/\" -->', $ssi->renderIncludeTag('/'));\n    }\n\n    public function testProcessDoesNothingIfContentTypeIsNotHtml()\n    {\n        $ssi = new Ssi();\n\n        $request = Request::create('/');\n        $response = new Response();\n        $response->headers->set('Content-Type', 'text/plain');\n        $ssi->process($request, $response);\n\n        $this->assertFalse($response->headers->has('x-body-eval'));\n    }\n\n    public function testProcess()\n    {\n        $ssi = new Ssi();\n\n        $request = Request::create('/');\n        $response = new Response('foo <!--#include virtual=\"...\" -->');\n        $ssi->process($request, $response);\n\n        $content = explode(substr($response->getContent(), 0, 24), $response->getContent());\n        $this->assertSame(['', 'foo ', \"...\\n\\n\\n\", ''], $content);\n        $this->assertEquals('SSI', $response->headers->get('x-body-eval'));\n\n        $response = new Response('foo <!--#include virtual=\"foo\\'\" -->');\n        $ssi->process($request, $response);\n\n        $content = explode(substr($response->getContent(), 0, 24), $response->getContent());\n        $this->assertSame(['', 'foo ', \"foo'\\n\\n\\n\", ''], $content);\n    }\n\n    public function testProcessEscapesPhpTags()\n    {\n        $ssi = new Ssi();\n\n        $request = Request::create('/');\n        $response = new Response('<?php <? <% <script language=php>');\n        $ssi->process($request, $response);\n\n        $content = explode(substr($response->getContent(), 0, 24), $response->getContent());\n        $this->assertSame(['', '<?php <? <% <script language=php>', ''], $content);\n    }\n\n    public function testProcessWhenNoSrcInAnSsi()\n    {\n        $this->expectException(\\RuntimeException::class);\n        $ssi = new Ssi();\n\n        $request = Request::create('/');\n        $response = new Response('foo <!--#include -->');\n        $ssi->process($request, $response);\n    }\n\n    public function testProcessRemoveSurrogateControlHeader()\n    {\n        $ssi = new Ssi();\n\n        $request = Request::create('/');\n        $response = new Response('foo <!--#include virtual=\"...\" -->');\n        $response->headers->set('Surrogate-Control', 'content=\"SSI/1.0\"');\n        $ssi->process($request, $response);\n        $this->assertEquals('SSI', $response->headers->get('x-body-eval'));\n\n        $response->headers->set('Surrogate-Control', 'no-store, content=\"SSI/1.0\"');\n        $ssi->process($request, $response);\n        $this->assertEquals('SSI', $response->headers->get('x-body-eval'));\n        $this->assertEquals('no-store', $response->headers->get('surrogate-control'));\n\n        $response->headers->set('Surrogate-Control', 'content=\"SSI/1.0\", no-store');\n        $ssi->process($request, $response);\n        $this->assertEquals('SSI', $response->headers->get('x-body-eval'));\n        $this->assertEquals('no-store', $response->headers->get('surrogate-control'));\n    }\n\n    public function testHandle()\n    {\n        $ssi = new Ssi();\n        $cache = $this->getCache(Request::create('/'), new Response('foo'));\n        $this->assertEquals('foo', $ssi->handle($cache, '/', '/alt', true));\n    }\n\n    public function testHandleWhenResponseIsNot200()\n    {\n        $this->expectException(\\RuntimeException::class);\n        $ssi = new Ssi();\n        $response = new Response('foo');\n        $response->setStatusCode(404);\n        $cache = $this->getCache(Request::create('/'), $response);\n        $ssi->handle($cache, '/', '/alt', false);\n    }\n\n    public function testHandleWhenResponseIsNot200AndErrorsAreIgnored()\n    {\n        $ssi = new Ssi();\n        $response = new Response('foo');\n        $response->setStatusCode(404);\n        $cache = $this->getCache(Request::create('/'), $response);\n        $this->assertEquals('', $ssi->handle($cache, '/', '/alt', true));\n    }\n\n    public function testHandleWhenResponseIsNot200AndAltIsPresent()\n    {\n        $ssi = new Ssi();\n        $response1 = new Response('foo');\n        $response1->setStatusCode(404);\n        $response2 = new Response('bar');\n        $cache = $this->getCache(Request::create('/'), [$response1, $response2]);\n        $this->assertEquals('bar', $ssi->handle($cache, '/', '/alt', false));\n    }\n\n    protected function getCache($request, $response)\n    {\n        $cache = $this->getMockBuilder(HttpCache::class)->onlyMethods(['getRequest', 'handle'])->disableOriginalConstructor()->getMock();\n        $cache->expects($this->atLeastOnce())\n              ->method('getRequest')\n              ->willReturn($request)\n        ;\n        if (\\is_array($response)) {\n            $cache\n                  ->method('handle')\n                  ->willReturn(...$response)\n            ;\n        } else {\n            $cache\n                  ->method('handle')\n                  ->willReturn($response)\n            ;\n        }\n\n        return $cache;\n    }\n}\n"
  },
  {
    "path": "Tests/HttpCache/StoreTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\HttpCache;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Cookie;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\Store;\n\nclass StoreTest extends TestCase\n{\n    protected Request $request;\n    protected Response $response;\n    protected Store $store;\n\n    protected function setUp(): void\n    {\n        $this->request = Request::create('/');\n        $this->response = new Response('hello world', 200, []);\n\n        HttpCacheTestCase::clearDirectory(sys_get_temp_dir().'/http_cache');\n\n        $this->store = new Store(sys_get_temp_dir().'/http_cache');\n    }\n\n    protected function tearDown(): void\n    {\n        HttpCacheTestCase::clearDirectory(sys_get_temp_dir().'/http_cache');\n    }\n\n    public function testReadsAnEmptyArrayWithReadWhenNothingCachedAtKey()\n    {\n        $this->assertSame([], $this->getStoreMetadata('/nothing'));\n    }\n\n    public function testUnlockFileThatDoesExist()\n    {\n        $this->storeSimpleEntry();\n        $this->store->lock($this->request);\n\n        $this->assertTrue($this->store->unlock($this->request));\n    }\n\n    public function testUnlockFileThatDoesNotExist()\n    {\n        $this->assertFalse($this->store->unlock($this->request));\n    }\n\n    public function testRemovesEntriesForKeyWithPurge()\n    {\n        $request = Request::create('/foo');\n        $this->store->write($request, new Response('foo'));\n\n        $metadata = $this->getStoreMetadata($request);\n        $this->assertNotEmpty($metadata);\n\n        $this->assertTrue($this->store->purge('/foo'));\n        $this->assertSame([], $this->getStoreMetadata($request));\n\n        // cached content should be kept after purging\n        $path = $this->store->getPath($metadata[0][1]['x-content-digest'][0]);\n        $this->assertTrue(is_file($path));\n\n        $this->assertFalse($this->store->purge('/bar'));\n    }\n\n    public function testStoresACacheEntry()\n    {\n        $cacheKey = $this->storeSimpleEntry();\n\n        $this->assertNotEmpty($this->getStoreMetadata($cacheKey));\n    }\n\n    public function testSetsTheXContentDigestResponseHeaderBeforeStoring()\n    {\n        $cacheKey = $this->storeSimpleEntry();\n        $entries = $this->getStoreMetadata($cacheKey);\n        [, $res] = $entries[0];\n\n        $this->assertEquals('en6c78e0e3bd51d358d01e758642b85fb8', $res['x-content-digest'][0]);\n    }\n\n    public function testDoesNotTrustXContentDigestFromUpstream()\n    {\n        $response = new Response('test', 200, ['X-Content-Digest' => 'untrusted-from-elsewhere']);\n\n        $cacheKey = $this->store->write($this->request, $response);\n        $entries = $this->getStoreMetadata($cacheKey);\n        [, $res] = $entries[0];\n\n        $this->assertEquals('en6c78e0e3bd51d358d01e758642b85fb8', $res['x-content-digest'][0]);\n        $this->assertEquals('en6c78e0e3bd51d358d01e758642b85fb8', $response->headers->get('X-Content-Digest'));\n    }\n\n    public function testWritesResponseEvenIfXContentDigestIsPresent()\n    {\n        // Prime the store\n        $this->store->write($this->request, new Response('test', 200, ['X-Content-Digest' => 'untrusted-from-elsewhere']));\n\n        $response = $this->store->lookup($this->request);\n        $this->assertNotNull($response);\n    }\n\n    public function testWritingARestoredResponseDoesNotCorruptCache()\n    {\n        /*\n         * This covers the regression reported in https://github.com/symfony/symfony/issues/37174.\n         *\n         * A restored response does *not* load the body, but only keep the file path in a special X-Body-File\n         * header. For reasons (?), the file path was also used as the restored response body.\n         * It would be up to others (HttpCache...?) to honor this header and actually load the response content\n         * from there.\n         *\n         * When a restored response was stored again, the Store itself would ignore the header. In the first\n         * step, this would compute a new Content Digest based on the file path in the restored response body;\n         * this is covered by \"Checkpoint 1\" below. But, since the X-Body-File header was left untouched (Checkpoint 2), downstream\n         * code (HttpCache...) would not immediately notice.\n         *\n         * Only upon performing the lookup for a second time, we'd get a Response where the (wrong) Content Digest\n         * is also reflected in the X-Body-File header, this time also producing wrong content when the downstream\n         * evaluates it.\n         */\n        $this->store->write($this->request, $this->response);\n        $digest = $this->response->headers->get('X-Content-Digest');\n        $path = $this->getStorePath($digest);\n\n        $response = $this->store->lookup($this->request);\n        $this->store->write($this->request, $response);\n        $this->assertEquals($digest, $response->headers->get('X-Content-Digest')); // Checkpoint 1\n        $this->assertEquals($path, $response->headers->get('X-Body-File')); // Checkpoint 2\n\n        $response = $this->store->lookup($this->request);\n        $this->assertEquals($digest, $response->headers->get('X-Content-Digest'));\n        $this->assertEquals($path, $response->headers->get('X-Body-File'));\n    }\n\n    public function testFindsAStoredEntryWithLookup()\n    {\n        $this->storeSimpleEntry();\n        $response = $this->store->lookup($this->request);\n\n        $this->assertNotNull($response);\n        $this->assertInstanceOf(Response::class, $response);\n    }\n\n    public function testDoesNotFindAnEntryWithLookupWhenNoneExists()\n    {\n        $request = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']);\n\n        $this->assertNull($this->store->lookup($request));\n    }\n\n    public function testCanonizesUrlsForCacheKeys()\n    {\n        $this->storeSimpleEntry($path = '/test?x=y&p=q');\n        $hitsReq = Request::create($path);\n        $missReq = Request::create('/test?p=x');\n\n        $this->assertNotNull($this->store->lookup($hitsReq));\n        $this->assertNull($this->store->lookup($missReq));\n    }\n\n    public function testDoesNotFindAnEntryWithLookupWhenTheBodyDoesNotExist()\n    {\n        $this->storeSimpleEntry();\n        $this->assertNotNull($this->response->headers->get('X-Content-Digest'));\n        $path = $this->getStorePath($this->response->headers->get('X-Content-Digest'));\n        @unlink($path);\n        $this->assertNull($this->store->lookup($this->request));\n    }\n\n    public function testRestoresResponseHeadersProperlyWithLookup()\n    {\n        $this->storeSimpleEntry();\n        $response = $this->store->lookup($this->request);\n\n        $this->assertEquals($response->headers->all(), array_merge(['content-length' => 4, 'x-body-file' => [$this->getStorePath($response->headers->get('X-Content-Digest'))]], $this->response->headers->all()));\n    }\n\n    public function testRestoresResponseContentFromEntityStoreWithLookup()\n    {\n        $this->storeSimpleEntry();\n        $response = $this->store->lookup($this->request);\n        $this->assertEquals($this->getStorePath('en'.hash('xxh128', 'test')), $response->headers->get('X-Body-File'));\n    }\n\n    public function testInvalidatesMetaAndEntityStoreEntriesWithInvalidate()\n    {\n        $this->storeSimpleEntry();\n        $this->store->invalidate($this->request);\n        $response = $this->store->lookup($this->request);\n        $this->assertInstanceOf(Response::class, $response);\n        $this->assertFalse($response->isFresh());\n    }\n\n    public function testSucceedsQuietlyWhenInvalidateCalledWithNoMatchingEntries()\n    {\n        $req = Request::create('/test');\n        $this->store->invalidate($req);\n        $this->assertNull($this->store->lookup($this->request));\n    }\n\n    public function testDoesNotReturnEntriesThatVaryWithLookup()\n    {\n        $req1 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']);\n        $req2 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam']);\n        $res = new Response('test', 200, ['Vary' => 'Foo Bar']);\n        $this->store->write($req1, $res);\n\n        $this->assertNull($this->store->lookup($req2));\n    }\n\n    public function testDoesNotReturnEntriesThatSlightlyVaryWithLookup()\n    {\n        $req1 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']);\n        $req2 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bam']);\n        $res = new Response('test', 200, ['Vary' => ['Foo', 'Bar']]);\n        $this->store->write($req1, $res);\n\n        $this->assertNull($this->store->lookup($req2));\n    }\n\n    public function testStoresMultipleResponsesForEachVaryCombination()\n    {\n        $req1 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']);\n        $res1 = new Response('test 1', 200, ['Vary' => 'Foo Bar']);\n        $key = $this->store->write($req1, $res1);\n\n        $req2 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam']);\n        $res2 = new Response('test 2', 200, ['Vary' => 'Foo Bar']);\n        $this->store->write($req2, $res2);\n\n        $req3 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Baz', 'HTTP_BAR' => 'Boom']);\n        $res3 = new Response('test 3', 200, ['Vary' => 'Foo Bar']);\n        $this->store->write($req3, $res3);\n\n        $this->assertEquals($this->getStorePath('en'.hash('xxh128', 'test 3')), $this->store->lookup($req3)->headers->get('X-Body-File'));\n        $this->assertEquals($this->getStorePath('en'.hash('xxh128', 'test 2')), $this->store->lookup($req2)->headers->get('X-Body-File'));\n        $this->assertEquals($this->getStorePath('en'.hash('xxh128', 'test 1')), $this->store->lookup($req1)->headers->get('X-Body-File'));\n\n        $this->assertCount(3, $this->getStoreMetadata($key));\n    }\n\n    public function testOverwritesNonVaryingResponseWithStore()\n    {\n        $req1 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']);\n        $res1 = new Response('test 1', 200, ['Vary' => 'Foo Bar']);\n        $this->store->write($req1, $res1);\n        $this->assertEquals($this->getStorePath('en'.hash('xxh128', 'test 1')), $this->store->lookup($req1)->headers->get('X-Body-File'));\n\n        $req2 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam']);\n        $res2 = new Response('test 2', 200, ['Vary' => 'Foo Bar']);\n        $this->store->write($req2, $res2);\n        $this->assertEquals($this->getStorePath('en'.hash('xxh128', 'test 2')), $this->store->lookup($req2)->headers->get('X-Body-File'));\n\n        $req3 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']);\n        $res3 = new Response('test 3', 200, ['Vary' => 'Foo Bar']);\n        $key = $this->store->write($req3, $res3);\n        $this->assertEquals($this->getStorePath('en'.hash('xxh128', 'test 3')), $this->store->lookup($req3)->headers->get('X-Body-File'));\n\n        $this->assertCount(2, $this->getStoreMetadata($key));\n    }\n\n    public function testLocking()\n    {\n        $req = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']);\n        $this->assertTrue($this->store->lock($req));\n\n        $this->store->lock($req);\n        $this->assertTrue($this->store->isLocked($req));\n\n        $this->store->unlock($req);\n        $this->assertFalse($this->store->isLocked($req));\n    }\n\n    public function testPurgeHttps()\n    {\n        $request = Request::create('https://example.com/foo');\n        $this->store->write($request, new Response('foo'));\n\n        $this->assertNotEmpty($this->getStoreMetadata($request));\n\n        $this->assertTrue($this->store->purge('https://example.com/foo'));\n        $this->assertSame([], $this->getStoreMetadata($request));\n    }\n\n    public function testPurgeHttpAndHttps()\n    {\n        $requestHttp = Request::create('https://example.com/foo');\n        $this->store->write($requestHttp, new Response('foo'));\n\n        $requestHttps = Request::create('http://example.com/foo');\n        $this->store->write($requestHttps, new Response('foo'));\n\n        $this->assertNotEmpty($this->getStoreMetadata($requestHttp));\n        $this->assertNotEmpty($this->getStoreMetadata($requestHttps));\n\n        $this->assertTrue($this->store->purge('http://example.com/foo'));\n        $this->assertSame([], $this->getStoreMetadata($requestHttp));\n        $this->assertSame([], $this->getStoreMetadata($requestHttps));\n    }\n\n    public function testDoesNotStorePrivateHeaders()\n    {\n        $request = Request::create('https://example.com/foo');\n        $response = new Response('foo');\n        $response->headers->setCookie(Cookie::fromString('foo=bar'));\n\n        $this->store->write($request, $response);\n        $this->assertArrayNotHasKey('set-cookie', $this->getStoreMetadata($request)[0][1]);\n        $this->assertNotEmpty($response->headers->getCookies());\n    }\n\n    public function testDiscardsInvalidBodyEval()\n    {\n        $request = Request::create('https://example.com/foo');\n        $response = new Response('foo', 200, ['X-Body-Eval' => 'SSI']);\n\n        $this->store->write($request, $response);\n        $this->assertNull($this->store->lookup($request));\n\n        $request = Request::create('https://example.com/foo');\n        $content = str_repeat('a', 24).'b'.str_repeat('a', 24).'b';\n        $response = new Response($content, 200, ['X-Body-Eval' => 'SSI']);\n\n        $this->store->write($request, $response);\n        $this->assertNull($this->store->lookup($request));\n    }\n\n    public function testLoadsBodyEval()\n    {\n        $request = Request::create('https://example.com/foo');\n        $content = str_repeat('a', 24).'b'.str_repeat('a', 24);\n        $response = new Response($content, 200, ['X-Body-Eval' => 'SSI']);\n\n        $this->store->write($request, $response);\n        $response = $this->store->lookup($request);\n        $this->assertSame($content, $response->getContent());\n    }\n\n    /**\n     * Basic case when the second header has a different value.\n     * Both responses should be cached.\n     */\n    public function testWriteWithMultipleVaryAndCachedAllResponse()\n    {\n        $req1 = Request::create('/foo', 'get', [], [], [], ['HTTP_FOO' => 'foo', 'HTTP_BAR' => 'bar']);\n        $content = str_repeat('a', 24).'b'.str_repeat('a', 24);\n        $res1 = new Response($content, 200, ['vary' => ['Foo', 'Bar'], 'X-Body-Eval' => 'SSI']);\n        $this->store->write($req1, $res1);\n\n        $responseLook = $this->store->lookup($req1);\n        $this->assertSame($content, $responseLook->getContent());\n\n        $req2 = Request::create('/foo', 'get', [], [], [], ['HTTP_FOO' => 'foo', 'HTTP_BAR' => 'foobar']);\n        $content2 = str_repeat('b', 24).'a'.str_repeat('b', 24);\n        $res2 = new Response($content2, 200, ['vary' => ['Foo', 'Bar'], 'X-Body-Eval' => 'SSI']);\n        $this->store->write($req2, $res2);\n\n        $responseLook = $this->store->lookup($req2);\n        $this->assertSame($content2, $responseLook->getContent());\n\n        $responseLook = $this->store->lookup($req1);\n        $this->assertSame($content, $responseLook->getContent());\n    }\n\n    /**\n     * Basic case when the second header has the same value on both requests.\n     * The last response should be cached.\n     */\n    public function testWriteWithMultipleVaryAndCachedLastResponse()\n    {\n        $req1 = Request::create('/foo', 'get', [], [], [], ['HTTP_FOO' => 'foo', 'HTTP_BAR' => 'bar']);\n        $content = str_repeat('a', 24).'b'.str_repeat('a', 24);\n        $res1 = new Response($content, 200, ['vary' => ['Foo', 'Bar'], 'X-Body-Eval' => 'SSI']);\n        $this->store->write($req1, $res1);\n\n        $responseLook = $this->store->lookup($req1);\n        $this->assertSame($content, $responseLook->getContent());\n\n        $req2 = Request::create('/foo', 'get', [], [], [], ['HTTP_FOO' => 'foo', 'HTTP_BAR' => 'bar']);\n        $content2 = str_repeat('b', 24).'a'.str_repeat('b', 24);\n        $res2 = new Response($content2, 200, ['vary' => ['Foo', 'Bar'], 'X-Body-Eval' => 'SSI']);\n        $this->store->write($req2, $res2);\n\n        $responseLook = $this->store->lookup($req2);\n        $this->assertSame($content2, $responseLook->getContent());\n\n        $responseLook = $this->store->lookup($req1);\n        $this->assertSame($content2, $responseLook->getContent());\n    }\n\n    /**\n     * Case when a vary value has been removed.\n     * Both responses should be cached.\n     */\n    public function testWriteWithChangingVary()\n    {\n        $req1 = Request::create('/foo', 'get', [], [], [], ['HTTP_FOO' => 'foo', 'HTTP_BAR' => 'bar']);\n        $content = str_repeat('a', 24).'b'.str_repeat('a', 24);\n        $res1 = new Response($content, 200, ['vary' => ['Foo', 'bar', 'foobar'], 'X-Body-Eval' => 'SSI']);\n        $this->store->write($req1, $res1);\n\n        $req2 = Request::create('/foo', 'get', [], [], [], ['HTTP_FOO' => 'foo', 'HTTP_FOOBAR' => 'bar']);\n        $content2 = str_repeat('b', 24).'a'.str_repeat('b', 24);\n        $res2 = new Response($content2, 200, ['vary' => ['Foo', 'foobar'], 'X-Body-Eval' => 'SSI']);\n        $this->store->write($req2, $res2);\n\n        $responseLook = $this->store->lookup($req2);\n        $this->assertSame($content2, $responseLook->getContent());\n\n        $responseLook = $this->store->lookup($req1);\n        $this->assertSame($content, $responseLook->getContent());\n    }\n\n    /**\n     * Case when a vary value has been removed and headers of the new vary list are the same.\n     * The last response should be cached.\n     */\n    public function testWriteWithRemoveVaryAndAllHeadersOnTheList()\n    {\n        $req1 = Request::create('/foo', 'get', [], [], [], ['HTTP_FOO' => 'foo', 'HTTP_FOOBAR' => 'bar']);\n        $content = str_repeat('a', 24).'b'.str_repeat('a', 24);\n        $res1 = new Response($content, 200, ['vary' => ['Foo', 'bar', 'foobar'], 'X-Body-Eval' => 'SSI']);\n        $this->store->write($req1, $res1);\n\n        $req2 = Request::create('/foo', 'get', [], [], [], ['HTTP_FOO' => 'foo', 'HTTP_FOOBAR' => 'bar']);\n        $content2 = str_repeat('b', 24).'a'.str_repeat('b', 24);\n        $res2 = new Response($content2, 200, ['vary' => ['Foo', 'foobar'], 'X-Body-Eval' => 'SSI']);\n        $this->store->write($req2, $res2);\n\n        $responseLook = $this->store->lookup($req2);\n        $this->assertSame($content2, $responseLook->getContent());\n\n        $responseLook = $this->store->lookup($req1);\n        $this->assertSame($content2, $responseLook->getContent());\n    }\n\n    /**\n     * Case when a vary value has been added and headers of the new vary list are the same.\n     * The last response should be cached.\n     */\n    public function testWriteWithAddingVaryAndAllHeadersOnTheList()\n    {\n        $req1 = Request::create('/foo', 'get', [], [], [], ['HTTP_FOO' => 'foo', 'HTTP_FOOBAR' => 'bar']);\n        $content = str_repeat('a', 24).'b'.str_repeat('a', 24);\n        $res1 = new Response($content, 200, ['vary' => ['Foo', 'foobar'], 'X-Body-Eval' => 'SSI']);\n        $this->store->write($req1, $res1);\n\n        $req2 = Request::create('/foo', 'get', [], [], [], ['HTTP_FOO' => 'foo', 'HTTP_BAR' => 'foobar', 'HTTP_FOOBAR' => 'bar']);\n        $content2 = str_repeat('b', 24).'a'.str_repeat('b', 24);\n        $res2 = new Response($content2, 200, ['vary' => ['Foo', 'bar', 'foobar'], 'X-Body-Eval' => 'SSI']);\n        $this->store->write($req2, $res2);\n\n        $responseLook = $this->store->lookup($req2);\n        $this->assertSame($content2, $responseLook->getContent());\n\n        $responseLook = $this->store->lookup($req1);\n        $this->assertSame($content, $responseLook->getContent());\n    }\n\n    protected function storeSimpleEntry($path = null, $headers = [])\n    {\n        $path ??= '/test';\n\n        $this->request = Request::create($path, 'get', [], [], [], $headers);\n        $this->response = new Response('test', 200, ['Cache-Control' => 'max-age=420']);\n\n        return $this->store->write($this->request, $this->response);\n    }\n\n    protected function getStoreMetadata($key)\n    {\n        $r = new \\ReflectionObject($this->store);\n        $m = $r->getMethod('getMetadata');\n\n        if ($key instanceof Request) {\n            $m1 = $r->getMethod('getCacheKey');\n            $key = $m1->invoke($this->store, $key);\n        }\n\n        return $m->invoke($this->store, $key);\n    }\n\n    protected function getStorePath($key)\n    {\n        $r = new \\ReflectionObject($this->store);\n        $m = $r->getMethod('getPath');\n\n        return $m->invoke($this->store, $key);\n    }\n\n    public function testQueryMethodCacheKeyIncludesBody()\n    {\n        $response = new Response('test', 200, ['Cache-Control' => 'max-age=420']);\n\n        $request1 = Request::create('/', 'QUERY', [], [], [], [], '{\"query\": \"users\"}');\n        $request2 = Request::create('/', 'QUERY', [], [], [], [], '{\"query\": \"posts\"}');\n        $request3 = Request::create('/', 'QUERY', [], [], [], [], '{\"query\": \"users\"}');\n\n        $key1 = $this->store->write($request1, $response);\n        $key2 = $this->store->write($request2, $response);\n        $key3 = $this->store->write($request3, $response);\n\n        $this->assertNotSame($key1, $key2);\n        $this->assertSame($key1, $key3);\n\n        $this->assertNotEmpty($this->getStoreMetadata($key1));\n        $this->assertNotEmpty($this->getStoreMetadata($key2));\n\n        $this->assertNotNull($this->store->lookup($request1));\n        $this->assertNotNull($this->store->lookup($request2));\n        $this->assertNotNull($this->store->lookup($request3));\n    }\n\n    public function testQueryMethodCacheKeyDiffersFromGet()\n    {\n        $response = new Response('test', 200, ['Cache-Control' => 'max-age=420']);\n\n        $getRequest = Request::create('/');\n        $queryRequest = Request::create('/', 'QUERY', [], [], [], [], '{\"query\": \"test\"}');\n\n        $getKey = $this->store->write($getRequest, $response);\n        $queryKey = $this->store->write($queryRequest, $response);\n\n        $this->assertNotSame($getKey, $queryKey);\n\n        $this->assertNotEmpty($this->getStoreMetadata($getKey));\n        $this->assertNotEmpty($this->getStoreMetadata($queryKey));\n\n        $this->assertNotNull($this->store->lookup($getRequest));\n        $this->assertNotNull($this->store->lookup($queryRequest));\n    }\n\n    public function testOtherMethodsCacheKeyIgnoresBody()\n    {\n        $response1 = new Response('test 1', 200, ['Cache-Control' => 'max-age=420']);\n        $response2 = new Response('test 2', 200, ['Cache-Control' => 'max-age=420']);\n\n        $getRequest1 = Request::create('/', 'GET', [], [], [], [], '{\"data\": \"test\"}');\n        $getRequest2 = Request::create('/', 'GET', [], [], [], [], '{\"data\": \"different\"}');\n\n        $key1 = $this->store->write($getRequest1, $response1);\n        $key2 = $this->store->write($getRequest2, $response2);\n\n        $this->assertSame($key1, $key2);\n\n        $lookup1 = $this->store->lookup($getRequest1);\n        $lookup2 = $this->store->lookup($getRequest2);\n        $this->assertNotNull($lookup1);\n        $this->assertNotNull($lookup2);\n\n        $this->assertCount(1, $this->getStoreMetadata($key1));\n        $this->assertSame($lookup1->getContent(), $lookup2->getContent());\n    }\n\n    public function testQueryMethodCacheKeyAvoidsBoundaryCollisions()\n    {\n        $response = new Response('test', 200, ['Cache-Control' => 'max-age=420']);\n\n        $request1 = Request::create('/api/query', 'QUERY', [], [], [], [], 'test');\n        $request2 = Request::create('/api/que', 'QUERY', [], [], [], [], 'rytest');\n\n        $key1 = $this->store->write($request1, $response);\n        $key2 = $this->store->write($request2, $response);\n\n        $this->assertNotSame($key1, $key2);\n\n        $this->assertNotEmpty($this->getStoreMetadata($key1));\n        $this->assertNotEmpty($this->getStoreMetadata($key2));\n\n        $this->assertNotNull($this->store->lookup($request1));\n        $this->assertNotNull($this->store->lookup($request2));\n    }\n}\n"
  },
  {
    "path": "Tests/HttpCache/SubRequestHandlerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\HttpCache;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\SubRequestHandler;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\n\nclass SubRequestHandlerTest extends TestCase\n{\n    private static array $globalState;\n\n    protected function setUp(): void\n    {\n        self::$globalState = $this->getGlobalState();\n    }\n\n    protected function tearDown(): void\n    {\n        Request::setTrustedProxies(self::$globalState[0], self::$globalState[1]);\n    }\n\n    public function testTrustedHeadersAreKept()\n    {\n        Request::setTrustedProxies(['10.0.0.1'], -1);\n        $globalState = $this->getGlobalState();\n\n        $request = Request::create('/');\n        $request->server->set('REMOTE_ADDR', '10.0.0.1');\n        $request->headers->set('X-Forwarded-For', '10.0.0.2');\n        $request->headers->set('X-Forwarded-Host', 'Good');\n        $request->headers->set('X-Forwarded-Port', '1234');\n        $request->headers->set('X-Forwarded-Proto', 'https');\n        $request->headers->set('X-Forwarded-Prefix', '/admin');\n\n        $kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) {\n            $this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR'));\n            $this->assertSame('10.0.0.2', $request->getClientIp());\n            $this->assertSame('Good', $request->headers->get('X-Forwarded-Host'));\n            $this->assertSame('1234', $request->headers->get('X-Forwarded-Port'));\n            $this->assertSame('https', $request->headers->get('X-Forwarded-Proto'));\n            $this->assertSame('/admin', $request->headers->get('X-Forwarded-Prefix'));\n        });\n\n        SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MAIN_REQUEST, true);\n\n        $this->assertSame($globalState, $this->getGlobalState());\n    }\n\n    public function testUntrustedHeadersAreRemoved()\n    {\n        $request = Request::create('/');\n        $request->server->set('REMOTE_ADDR', '10.0.0.1');\n        $request->headers->set('X-Forwarded-For', '10.0.0.2');\n        $request->headers->set('X-Forwarded-Host', 'Evil');\n        $request->headers->set('X-Forwarded-Port', '1234');\n        $request->headers->set('X-Forwarded-Proto', 'http');\n        $request->headers->set('X-Forwarded-Prefix', '/admin');\n        $request->headers->set('Forwarded', 'Evil2');\n\n        $kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) {\n            $this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR'));\n            $this->assertSame('10.0.0.1', $request->getClientIp());\n            $this->assertFalse($request->headers->has('X-Forwarded-Host'));\n            $this->assertFalse($request->headers->has('X-Forwarded-Port'));\n            $this->assertFalse($request->headers->has('X-Forwarded-Proto'));\n            $this->assertFalse($request->headers->has('X-Forwarded-Prefix'));\n            $this->assertSame('for=\"10.0.0.1\";host=\"localhost\";proto=http', $request->headers->get('Forwarded'));\n        });\n\n        SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MAIN_REQUEST, true);\n\n        $this->assertSame(self::$globalState, $this->getGlobalState());\n    }\n\n    public function testTrustedForwardedHeader()\n    {\n        Request::setTrustedProxies(['10.0.0.1'], -1);\n        $globalState = $this->getGlobalState();\n\n        $request = Request::create('/');\n        $request->server->set('REMOTE_ADDR', '10.0.0.1');\n        $request->headers->set('Forwarded', 'for=\"10.0.0.2\";host=\"foo.bar:1234\";proto=https');\n\n        $kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) {\n            $this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR'));\n            $this->assertSame('10.0.0.2', $request->getClientIp());\n            $this->assertSame('foo.bar:1234', $request->getHttpHost());\n            $this->assertSame('https', $request->getScheme());\n            $this->assertSame(1234, $request->getPort());\n        });\n\n        SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MAIN_REQUEST, true);\n\n        $this->assertSame($globalState, $this->getGlobalState());\n    }\n\n    public function testTrustedXForwardedForHeader()\n    {\n        Request::setTrustedProxies(['10.0.0.1'], -1);\n        $globalState = $this->getGlobalState();\n\n        $request = Request::create('/');\n        $request->server->set('REMOTE_ADDR', '10.0.0.1');\n        $request->headers->set('X-Forwarded-For', '10.0.0.2');\n        $request->headers->set('X-Forwarded-Host', 'foo.bar');\n        $request->headers->set('X-Forwarded-Proto', 'https');\n        $request->headers->set('X-Forwarded-Prefix', '/admin');\n\n        $kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) {\n            $this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR'));\n            $this->assertSame('10.0.0.2', $request->getClientIp());\n            $this->assertSame('foo.bar', $request->getHttpHost());\n            $this->assertSame('https', $request->getScheme());\n            $this->assertSame('/admin', $request->getBaseUrl());\n        });\n\n        SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MAIN_REQUEST, true);\n\n        $this->assertSame($globalState, $this->getGlobalState());\n    }\n\n    private function getGlobalState(): array\n    {\n        return [\n            Request::getTrustedProxies(),\n            Request::getTrustedHeaderSet(),\n        ];\n    }\n}\n\nclass TestSubRequestHandlerKernel implements HttpKernelInterface\n{\n    public function __construct(\n        private \\Closure $assertCallback,\n    ) {\n    }\n\n    public function handle(Request $request, $type = self::MAIN_REQUEST, $catch = true): Response\n    {\n        $assertCallback = $this->assertCallback;\n        $assertCallback($request, $type, $catch);\n\n        return new Response();\n    }\n}\n"
  },
  {
    "path": "Tests/HttpCache/TestHttpKernel.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\HttpCache;\n\nuse Symfony\\Component\\EventDispatcher\\EventDispatcher;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolverInterface;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface;\nuse Symfony\\Component\\HttpKernel\\HttpKernel;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\n\nclass TestHttpKernel extends HttpKernel implements ControllerResolverInterface, ArgumentResolverInterface\n{\n    protected ?string $body = null;\n    protected int $status;\n    protected array $headers;\n    protected bool $called = false;\n    protected ?\\Closure $customizer;\n    protected bool $catch = false;\n    protected array $backendRequest;\n\n    public function __construct($body, $status, $headers, ?\\Closure $customizer = null, ?EventDispatcher $eventDispatcher = null)\n    {\n        $this->body = $body;\n        $this->status = $status;\n        $this->headers = $headers;\n        $this->customizer = $customizer;\n\n        parent::__construct($eventDispatcher ?? new EventDispatcher(), $this, null, $this);\n    }\n\n    public function assert(\\Closure $callback)\n    {\n        $trustedConfig = [Request::getTrustedProxies(), Request::getTrustedHeaderSet()];\n\n        [$trustedProxies, $trustedHeaderSet, $backendRequest] = $this->backendRequest;\n        Request::setTrustedProxies($trustedProxies, $trustedHeaderSet);\n\n        try {\n            $callback($backendRequest);\n        } finally {\n            [$trustedProxies, $trustedHeaderSet] = $trustedConfig;\n            Request::setTrustedProxies($trustedProxies, $trustedHeaderSet);\n        }\n    }\n\n    public function handle(Request $request, $type = HttpKernelInterface::MAIN_REQUEST, $catch = false): Response\n    {\n        $this->catch = $catch;\n        $this->backendRequest = [Request::getTrustedProxies(), Request::getTrustedHeaderSet(), $request];\n\n        return parent::handle($request, $type, $catch);\n    }\n\n    public function isCatchingExceptions()\n    {\n        return $this->catch;\n    }\n\n    public function getController(Request $request): callable|false\n    {\n        return $this->callController(...);\n    }\n\n    public function getArguments(Request $request, callable $controller, ?\\ReflectionFunctionAbstract $reflector = null): array\n    {\n        return [$request];\n    }\n\n    public function callController(Request $request)\n    {\n        $this->called = true;\n\n        $response = new Response($this->body, $this->status, $this->headers);\n\n        if (null !== $customizer = $this->customizer) {\n            $customizer($request, $response);\n        }\n\n        return $response;\n    }\n\n    public function hasBeenCalled()\n    {\n        return $this->called;\n    }\n\n    public function reset()\n    {\n        $this->called = false;\n    }\n}\n"
  },
  {
    "path": "Tests/HttpCache/TestMultipleHttpKernel.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\HttpCache;\n\nuse Symfony\\Component\\EventDispatcher\\EventDispatcher;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolverInterface;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface;\nuse Symfony\\Component\\HttpKernel\\HttpKernel;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\n\nclass TestMultipleHttpKernel extends HttpKernel implements ControllerResolverInterface, ArgumentResolverInterface\n{\n    protected array $bodies = [];\n    protected array $statuses = [];\n    protected array $headers = [];\n    protected bool $called = false;\n    protected Request $backendRequest;\n\n    public function __construct($responses)\n    {\n        foreach ($responses as $response) {\n            $this->bodies[] = $response['body'];\n            $this->statuses[] = $response['status'];\n            $this->headers[] = $response['headers'];\n        }\n\n        parent::__construct(new EventDispatcher(), $this, null, $this);\n    }\n\n    public function getBackendRequest()\n    {\n        return $this->backendRequest;\n    }\n\n    public function handle(Request $request, $type = HttpKernelInterface::MAIN_REQUEST, $catch = false): Response\n    {\n        $this->backendRequest = $request;\n\n        return parent::handle($request, $type, $catch);\n    }\n\n    public function getController(Request $request): callable|false\n    {\n        return $this->callController(...);\n    }\n\n    public function getArguments(Request $request, callable $controller, ?\\ReflectionFunctionAbstract $reflector = null): array\n    {\n        return [$request];\n    }\n\n    public function callController(Request $request)\n    {\n        $this->called = true;\n\n        $response = new Response(array_shift($this->bodies), array_shift($this->statuses), array_shift($this->headers));\n\n        return $response;\n    }\n\n    public function hasBeenCalled()\n    {\n        return $this->called;\n    }\n\n    public function reset()\n    {\n        $this->called = false;\n    }\n}\n"
  },
  {
    "path": "Tests/HttpClientKernelTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\HttpClientKernel;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\nclass HttpClientKernelTest extends TestCase\n{\n    public function testHandlePassesMaxRedirectsHttpClientOption()\n    {\n        $request = new Request();\n        $request->attributes->set('http_client_options', ['max_redirects' => 50]);\n\n        $response = $this->createStub(ResponseInterface::class);\n        $response->method('getStatusCode')->willReturn(200);\n\n        $client = $this->createMock(HttpClientInterface::class);\n        $client\n            ->expects($this->once())\n            ->method('request')\n            ->willReturnCallback(function (string $method, string $uri, array $options) use ($request, $response) {\n                $this->assertSame($request->getMethod(), $method);\n                $this->assertSame($request->getUri(), $uri);\n                $this->assertArrayHasKey('max_redirects', $options);\n                $this->assertSame(50, $options['max_redirects']);\n\n                return $response;\n            });\n\n        $kernel = new HttpClientKernel($client);\n        $kernel->handle($request);\n    }\n}\n"
  },
  {
    "path": "Tests/HttpKernelBrowserTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests;\n\nuse PHPUnit\\Framework\\Attributes\\Group;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Cookie;\nuse Symfony\\Component\\HttpFoundation\\File\\UploadedFile;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpFoundation\\StreamedResponse;\nuse Symfony\\Component\\HttpKernel\\HttpKernelBrowser;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\MockableUploadFileWithClientSize;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\TestClient;\n\n#[Group('time-sensitive')]\nclass HttpKernelBrowserTest extends TestCase\n{\n    public function testDoRequest()\n    {\n        $client = new HttpKernelBrowser(new TestHttpKernel());\n\n        $client->request('GET', '/');\n        $this->assertEquals('Request: /', $client->getResponse()->getContent(), '->doRequest() uses the request handler to make the request');\n        $this->assertInstanceOf(\\Symfony\\Component\\BrowserKit\\Request::class, $client->getInternalRequest());\n        $this->assertInstanceOf(Request::class, $client->getRequest());\n        $this->assertInstanceOf(\\Symfony\\Component\\BrowserKit\\Response::class, $client->getInternalResponse());\n        $this->assertInstanceOf(Response::class, $client->getResponse());\n\n        $client->request('GET', 'http://www.example.com/');\n        $this->assertEquals('Request: /', $client->getResponse()->getContent(), '->doRequest() uses the request handler to make the request');\n        $this->assertEquals('www.example.com', $client->getRequest()->getHost(), '->doRequest() uses the request handler to make the request');\n\n        $client->request('GET', 'http://www.example.com/?parameter=http://example.com');\n        $this->assertEquals('http://www.example.com/?parameter='.urlencode('http://example.com'), $client->getRequest()->getUri(), '->doRequest() uses the request handler to make the request');\n    }\n\n    public function testGetScript()\n    {\n        $client = new TestClient(new TestHttpKernel());\n        $client->insulate();\n        $client->request('GET', '/');\n\n        $this->assertEquals('Request: /', $client->getResponse()->getContent(), '->getScript() returns a script that uses the request handler to make the request');\n    }\n\n    public function testFilterResponseConvertsCookies()\n    {\n        $client = new HttpKernelBrowser(new TestHttpKernel());\n\n        $r = new \\ReflectionObject($client);\n        $m = $r->getMethod('filterResponse');\n\n        $response = new Response();\n        $response->headers->setCookie($cookie1 = new Cookie('foo', 'bar', \\DateTimeImmutable::createFromFormat('j-M-Y H:i:s T', '15-Feb-2009 20:00:00 GMT')->format('U'), '/foo', 'http://example.com', true, true, false, null));\n        $domResponse = $m->invoke($client, $response);\n        $this->assertSame((string) $cookie1, $domResponse->getHeader('Set-Cookie'));\n\n        $response = new Response();\n        $response->headers->setCookie($cookie1 = new Cookie('foo', 'bar', \\DateTimeImmutable::createFromFormat('j-M-Y H:i:s T', '15-Feb-2009 20:00:00 GMT')->format('U'), '/foo', 'http://example.com', true, true, false, null));\n        $response->headers->setCookie($cookie2 = new Cookie('foo1', 'bar1', \\DateTimeImmutable::createFromFormat('j-M-Y H:i:s T', '15-Feb-2009 20:00:00 GMT')->format('U'), '/foo', 'http://example.com', true, true, false, null));\n        $domResponse = $m->invoke($client, $response);\n        $this->assertSame((string) $cookie1, $domResponse->getHeader('Set-Cookie'));\n        $this->assertSame([(string) $cookie1, (string) $cookie2], $domResponse->getHeader('Set-Cookie', false));\n    }\n\n    public function testFilterResponseSupportsStreamedResponses()\n    {\n        $client = new HttpKernelBrowser(new TestHttpKernel());\n\n        $r = new \\ReflectionObject($client);\n        $m = $r->getMethod('filterResponse');\n\n        $response = new StreamedResponse(static function () {\n            echo 'foo';\n        });\n\n        $domResponse = $m->invoke($client, $response);\n        $this->assertEquals('foo', $domResponse->getContent());\n    }\n\n    public function testFilterResponseSupportsStreamedResponsesWithChunks()\n    {\n        $client = new HttpKernelBrowser(new TestHttpKernel());\n\n        $r = new \\ReflectionObject($client);\n        $m = $r->getMethod('filterResponse');\n\n        $response = new StreamedResponse(new \\ArrayIterator(['foo']));\n\n        $domResponse = $m->invoke($client, $response);\n        $this->assertEquals('foo', $domResponse->getContent());\n    }\n\n    public function testUploadedFile()\n    {\n        $source = tempnam(sys_get_temp_dir(), 'source');\n        file_put_contents($source, '1');\n        $target = sys_get_temp_dir().'/sf.moved.file';\n        @unlink($target);\n\n        $kernel = new TestHttpKernel();\n        $client = new HttpKernelBrowser($kernel);\n\n        $files = [\n            ['tmp_name' => $source, 'name' => 'original', 'type' => 'mime/original', 'size' => null, 'error' => \\UPLOAD_ERR_OK],\n            new UploadedFile($source, 'original', 'mime/original', \\UPLOAD_ERR_OK, true),\n        ];\n\n        $file = null;\n        foreach ($files as $file) {\n            $client->request('POST', '/', [], ['foo' => $file]);\n\n            $files = $client->getRequest()->files->all();\n\n            $this->assertCount(1, $files);\n\n            $file = $files['foo'];\n\n            $this->assertEquals('original', $file->getClientOriginalName());\n            $this->assertEquals('mime/original', $file->getClientMimeType());\n            $this->assertEquals(1, $file->getSize());\n        }\n\n        $file->move(\\dirname($target), basename($target));\n\n        $this->assertFileExists($target);\n        unlink($target);\n    }\n\n    public function testUploadedFileWhenNoFileSelected()\n    {\n        $kernel = new TestHttpKernel();\n        $client = new HttpKernelBrowser($kernel);\n\n        $file = ['tmp_name' => '', 'name' => '', 'type' => '', 'size' => 0, 'error' => \\UPLOAD_ERR_NO_FILE];\n\n        $client->request('POST', '/', [], ['foo' => $file]);\n\n        $files = $client->getRequest()->files->all();\n\n        $this->assertCount(1, $files);\n        $this->assertNull($files['foo']);\n    }\n\n    public function testUploadedFileWhenSizeExceedsUploadMaxFileSize()\n    {\n        if (UploadedFile::getMaxFilesize() > \\PHP_INT_MAX) {\n            $this->markTestSkipped('Requires PHP_INT_MAX to be greater than \"upload_max_filesize\" and \"post_max_size\" ini settings');\n        }\n\n        $source = tempnam(sys_get_temp_dir(), 'source');\n\n        $kernel = new TestHttpKernel();\n        $client = new HttpKernelBrowser($kernel);\n\n        $file = $this\n            ->getMockBuilder(MockableUploadFileWithClientSize::class)\n            ->setConstructorArgs([$source, 'original', 'mime/original', \\UPLOAD_ERR_OK, true])\n            ->onlyMethods(['getSize', 'getClientSize'])\n            ->getMock()\n        ;\n        /* should be modified when the getClientSize will be removed */\n        $file->expects($this->atLeastOnce())\n            ->method('getSize')\n            ->willReturn(\\PHP_INT_MAX)\n        ;\n        $file\n            ->method('getClientSize')\n            ->willReturn(\\PHP_INT_MAX)\n        ;\n\n        $client->request('POST', '/', [], [$file]);\n\n        $files = $client->getRequest()->files->all();\n\n        $this->assertCount(1, $files);\n\n        $file = $files[0];\n\n        $this->assertFalse($file->isValid());\n        $this->assertEquals(\\UPLOAD_ERR_INI_SIZE, $file->getError());\n        $this->assertEquals('mime/original', $file->getClientMimeType());\n        $this->assertEquals('original', $file->getClientOriginalName());\n        $this->assertEquals(0, $file->getSize());\n\n        unlink($source);\n    }\n\n    public function testAcceptHeaderNotSet()\n    {\n        $client = new HttpKernelBrowser(new TestHttpKernel());\n\n        $client->request('GET', '/');\n        $this->assertFalse($client->getRequest()->headers->has('Accept'));\n\n        $client->request('GET', '/', [], [], ['HTTP_ACCEPT' => 'application/ld+json']);\n        $this->assertSame('application/ld+json', $client->getRequest()->headers->get('Accept'));\n    }\n}\n"
  },
  {
    "path": "Tests/HttpKernelTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\EventDispatcher\\EventDispatcher;\nuse Symfony\\Component\\EventDispatcher\\EventDispatcherInterface;\nuse Symfony\\Component\\HttpFoundation\\RedirectResponse;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpFoundation\\StreamedResponse;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolverInterface;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface;\nuse Symfony\\Component\\HttpKernel\\Event\\ExceptionEvent;\nuse Symfony\\Component\\HttpKernel\\Exception\\AccessDeniedHttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\BadRequestHttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\ControllerDoesNotReturnResponseException;\nuse Symfony\\Component\\HttpKernel\\Exception\\MethodNotAllowedHttpException;\nuse Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;\nuse Symfony\\Component\\HttpKernel\\HttpKernel;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\Attribute\\Bar;\n\nclass HttpKernelTest extends TestCase\n{\n    /**\n     * Catch exceptions: true\n     * Throwable type: RuntimeException\n     * Listener: false.\n     */\n    public function testHandleWhenControllerThrowsAnExceptionAndCatchIsTrue()\n    {\n        $this->expectException(\\RuntimeException::class);\n        $kernel = $this->getHttpKernel(new EventDispatcher(), static fn () => throw new \\RuntimeException());\n\n        $kernel->handle(new Request(), HttpKernelInterface::MAIN_REQUEST, true);\n    }\n\n    public function testRequestStackIsNotBrokenWhenControllerThrowsAnExceptionAndCatchIsTrue()\n    {\n        $requestStack = new RequestStack();\n        $kernel = $this->getHttpKernel(new EventDispatcher(), static fn () => throw new \\RuntimeException(), $requestStack);\n\n        try {\n            $kernel->handle(new Request(), HttpKernelInterface::MAIN_REQUEST, true);\n        } catch (\\Throwable $exception) {\n        }\n\n        self::assertNull($requestStack->getCurrentRequest());\n    }\n\n    public function testRequestStackIsNotBrokenWhenControllerThrowsAnExceptionAndCatchIsFalse()\n    {\n        $requestStack = new RequestStack();\n        $kernel = $this->getHttpKernel(new EventDispatcher(), static fn () => throw new \\RuntimeException(), $requestStack);\n\n        try {\n            $kernel->handle(new Request(), HttpKernelInterface::MAIN_REQUEST, false);\n        } catch (\\Throwable $exception) {\n        }\n\n        self::assertNull($requestStack->getCurrentRequest());\n    }\n\n    public function testRequestStackIsNotBrokenWhenControllerThrowsAnThrowable()\n    {\n        $requestStack = new RequestStack();\n        $kernel = $this->getHttpKernel(new EventDispatcher(), static fn () => throw new \\Error(), $requestStack);\n\n        try {\n            $kernel->handle(new Request(), HttpKernelInterface::MAIN_REQUEST, true);\n        } catch (\\Throwable $exception) {\n        }\n\n        self::assertNull($requestStack->getCurrentRequest());\n    }\n\n    /**\n     * Catch exceptions: false\n     * Throwable type: RuntimeException\n     * Listener: false.\n     */\n    public function testHandleWhenControllerThrowsAnExceptionAndCatchIsFalseAndNoListenerIsRegistered()\n    {\n        $this->expectException(\\RuntimeException::class);\n        $kernel = $this->getHttpKernel(new EventDispatcher(), static fn () => throw new \\RuntimeException());\n\n        $kernel->handle(new Request(), HttpKernelInterface::MAIN_REQUEST, false);\n    }\n\n    /**\n     * Catch exceptions: true\n     * Throwable type: RuntimeException\n     * Listener: true.\n     */\n    public function testHandleWhenControllerThrowsAnExceptionAndCatchIsTrueWithAHandlingListener()\n    {\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::EXCEPTION, static function ($event) {\n            $event->setResponse(new Response($event->getThrowable()->getMessage()));\n        });\n\n        $kernel = $this->getHttpKernel($dispatcher, static fn () => throw new \\RuntimeException('foo'));\n        $response = $kernel->handle(new Request(), HttpKernelInterface::MAIN_REQUEST, true);\n\n        $this->assertEquals('500', $response->getStatusCode());\n        $this->assertEquals('foo', $response->getContent());\n    }\n\n    /**\n     * Catch exceptions: true\n     * Throwable type: TypeError\n     * Listener: true.\n     */\n    public function testHandleWhenControllerThrowsAThrowableAndCatchIsTrueWithAHandlingListener()\n    {\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::EXCEPTION, static function ($event) {\n            $event->setResponse(new Response($event->getThrowable()->getMessage()));\n        });\n\n        $kernel = $this->getHttpKernel($dispatcher, static fn () => throw new \\TypeError('foo'), handleAllThrowables: true);\n        $response = $kernel->handle(new Request(), HttpKernelInterface::MAIN_REQUEST, true);\n\n        $this->assertEquals('500', $response->getStatusCode());\n        $this->assertEquals('foo', $response->getContent());\n    }\n\n    /**\n     * Catch exceptions: false\n     * Throwable type: TypeError\n     * Listener: true.\n     */\n    public function testHandleWhenControllerThrowsAThrowableAndCatchIsFalseWithAHandlingListener()\n    {\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::EXCEPTION, static function ($event) {\n            $event->setResponse(new Response($event->getThrowable()->getMessage()));\n        });\n\n        $kernel = $this->getHttpKernel($dispatcher, static fn () => throw new \\TypeError('foo'), handleAllThrowables: true);\n        $this->expectException(\\TypeError::class);\n        $kernel->handle(new Request(), HttpKernelInterface::MAIN_REQUEST, false);\n    }\n\n    /**\n     * Catch exceptions: true\n     * Throwable type: TypeError\n     * Listener: true.\n     */\n    public function testHandleWhenControllerThrowsAThrowableAndCatchIsTrueNotHandlingThrowables()\n    {\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::EXCEPTION, static function ($event) {\n            $event->setResponse(new Response($event->getThrowable()->getMessage()));\n        });\n\n        $controllerResolver = $this->createStub(ControllerResolverInterface::class);\n        $controllerResolver\n            ->method('getController')\n            ->willReturn(static fn () => throw new \\TypeError('foo'));\n\n        $argumentResolver = $this->createStub(ArgumentResolverInterface::class);\n        $argumentResolver\n            ->method('getArguments')\n            ->willReturn([]);\n\n        $kernel = new HttpKernel($dispatcher, $controllerResolver, null, $argumentResolver);\n\n        $this->expectException(\\TypeError::class);\n        $kernel->handle(new Request(), HttpKernelInterface::MAIN_REQUEST, true);\n    }\n\n    /**\n     * Catch exceptions: true\n     * Throwable type: RuntimeException\n     * Listener: true.\n     */\n    public function testHandleWhenControllerThrowsAnExceptionAndCatchIsTrueWithANonHandlingListener()\n    {\n        $exception = new \\RuntimeException();\n\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::EXCEPTION, static function ($event) {\n            // should set a response, but does not\n        });\n\n        $kernel = $this->getHttpKernel($dispatcher, static fn () => throw $exception);\n\n        try {\n            $kernel->handle(new Request(), HttpKernelInterface::MAIN_REQUEST, true);\n            $this->fail('LogicException expected');\n        } catch (\\RuntimeException $e) {\n            $this->assertSame($exception, $e);\n        }\n    }\n\n    public function testHandleExceptionWithARedirectionResponse()\n    {\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::EXCEPTION, static function ($event) {\n            $event->setResponse(new RedirectResponse('/login', 301));\n        });\n\n        $kernel = $this->getHttpKernel($dispatcher, static fn () => throw new AccessDeniedHttpException());\n        $response = $kernel->handle(new Request());\n\n        $this->assertEquals('301', $response->getStatusCode());\n        $this->assertEquals('/login', $response->headers->get('Location'));\n    }\n\n    public function testHandleHttpException()\n    {\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::EXCEPTION, static function ($event) {\n            $event->setResponse(new Response($event->getThrowable()->getMessage()));\n        });\n\n        $kernel = $this->getHttpKernel($dispatcher, static fn () => throw new MethodNotAllowedHttpException(['POST']));\n        $response = $kernel->handle(new Request());\n\n        $this->assertEquals('405', $response->getStatusCode());\n        $this->assertEquals('POST', $response->headers->get('Allow'));\n    }\n\n    public function getStatusCodes()\n    {\n        return [\n            [200, 404],\n            [404, 200],\n            [301, 200],\n            [500, 200],\n        ];\n    }\n\n    #[DataProvider('getSpecificStatusCodes')]\n    public function testHandleWhenAnExceptionIsHandledWithASpecificStatusCode($expectedStatusCode)\n    {\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::EXCEPTION, static function (ExceptionEvent $event) use ($expectedStatusCode) {\n            $event->allowCustomResponseCode();\n            $event->setResponse(new Response('', $expectedStatusCode));\n        });\n\n        $kernel = $this->getHttpKernel($dispatcher, static fn () => throw new \\RuntimeException());\n        $response = $kernel->handle(new Request());\n\n        $this->assertEquals($expectedStatusCode, $response->getStatusCode());\n    }\n\n    public static function getSpecificStatusCodes()\n    {\n        return [\n            [200],\n            [302],\n            [403],\n        ];\n    }\n\n    public function testHandleWhenAListenerReturnsAResponse()\n    {\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::REQUEST, static function ($event) {\n            $event->setResponse(new Response('hello'));\n        });\n\n        $kernel = $this->getHttpKernel($dispatcher);\n\n        $this->assertEquals('hello', $kernel->handle(new Request())->getContent());\n    }\n\n    public function testHandleWhenNoControllerIsFound()\n    {\n        $this->expectException(NotFoundHttpException::class);\n        $dispatcher = new EventDispatcher();\n        $kernel = $this->getHttpKernel($dispatcher, false);\n\n        $kernel->handle(new Request());\n    }\n\n    public function testHandleWhenTheControllerIsAClosure()\n    {\n        $response = new Response('foo');\n        $dispatcher = new EventDispatcher();\n        $kernel = $this->getHttpKernel($dispatcher, static fn () => $response);\n\n        $this->assertSame($response, $kernel->handle(new Request()));\n    }\n\n    public function testHandleWhenTheControllerIsAnObjectWithInvoke()\n    {\n        $dispatcher = new EventDispatcher();\n        $kernel = $this->getHttpKernel($dispatcher, new TestController());\n\n        $this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request()));\n    }\n\n    public function testHandleWhenTheControllerIsAFunction()\n    {\n        $dispatcher = new EventDispatcher();\n        $kernel = $this->getHttpKernel($dispatcher, 'Symfony\\Component\\HttpKernel\\Tests\\controller_func');\n\n        $this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request()));\n    }\n\n    public function testHandleWhenTheControllerIsAnArray()\n    {\n        $dispatcher = new EventDispatcher();\n        $kernel = $this->getHttpKernel($dispatcher, [new TestController(), 'controller']);\n\n        $this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request()));\n    }\n\n    public function testHandleWhenTheControllerIsAStaticArray()\n    {\n        $dispatcher = new EventDispatcher();\n        $kernel = $this->getHttpKernel($dispatcher, ['Symfony\\Component\\HttpKernel\\Tests\\TestController', 'staticcontroller']);\n\n        $this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request()));\n    }\n\n    public function testHandleWhenTheControllerDoesNotReturnAResponse()\n    {\n        $dispatcher = new EventDispatcher();\n        $kernel = $this->getHttpKernel($dispatcher, static fn () => null);\n\n        try {\n            $kernel->handle(new Request());\n\n            $this->fail('The kernel should throw an exception.');\n        } catch (ControllerDoesNotReturnResponseException $e) {\n            $first = $e->getTrace()[0];\n\n            // `file` index the array starting at 0, and __FILE__ starts at 1\n            $line = file($first['file'])[$first['line'] - 2];\n            $this->assertStringContainsString('// call controller', $line);\n        }\n    }\n\n    public function testHandleWhenTheControllerDoesNotReturnAResponseButAViewIsRegistered()\n    {\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::VIEW, static function ($event) {\n            $event->setResponse(new Response($event->getControllerResult()));\n        });\n\n        $kernel = $this->getHttpKernel($dispatcher, static fn () => 'foo');\n\n        $this->assertEquals('foo', $kernel->handle(new Request())->getContent());\n    }\n\n    public function testHandleWithAResponseListener()\n    {\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::RESPONSE, static function ($event) {\n            $event->setResponse(new Response('foo'));\n        });\n        $kernel = $this->getHttpKernel($dispatcher);\n\n        $this->assertEquals('foo', $kernel->handle(new Request())->getContent());\n    }\n\n    public function testHandleAllowChangingControllerArguments()\n    {\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS, static function ($event) {\n            $event->setArguments(['foo']);\n        });\n\n        $kernel = $this->getHttpKernel($dispatcher, static fn ($content) => new Response($content));\n\n        $this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request()));\n    }\n\n    public function testHandleAllowChangingControllerAndArguments()\n    {\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS, static function ($event) {\n            $oldController = $event->getController();\n            $oldArguments = $event->getArguments();\n\n            $newController = static function ($id) use ($oldController, $oldArguments) {\n                $response = $oldController(...$oldArguments);\n\n                $response->headers->set('X-Id', $id);\n\n                return $response;\n            };\n\n            $event->setController($newController);\n            $event->setArguments(['bar']);\n        });\n\n        $kernel = $this->getHttpKernel($dispatcher, static fn ($content) => new Response($content), null, ['foo']);\n\n        $this->assertResponseEquals(new Response('foo', 200, ['X-Id' => 'bar']), $kernel->handle(new Request()));\n    }\n\n    public function testTerminate()\n    {\n        $dispatcher = new EventDispatcher();\n        $kernel = $this->getHttpKernel($dispatcher);\n        $dispatcher->addListener(KernelEvents::TERMINATE, static function ($event) use (&$called, &$capturedKernel, &$capturedRequest, &$capturedResponse) {\n            $called = true;\n            $capturedKernel = $event->getKernel();\n            $capturedRequest = $event->getRequest();\n            $capturedResponse = $event->getResponse();\n        });\n\n        $kernel->terminate($request = Request::create('/'), $response = new Response());\n        $this->assertTrue($called);\n        $this->assertEquals($kernel, $capturedKernel);\n        $this->assertEquals($request, $capturedRequest);\n        $this->assertEquals($response, $capturedResponse);\n    }\n\n    public function testTerminateWithException()\n    {\n        $dispatcher = new EventDispatcher();\n        $requestStack = new RequestStack();\n        $kernel = $this->getHttpKernel($dispatcher, null, $requestStack);\n\n        $dispatcher->addListener(KernelEvents::EXCEPTION, static function (ExceptionEvent $event) use (&$capturedRequest, $requestStack) {\n            $capturedRequest = $requestStack->getCurrentRequest();\n            $event->setResponse(new Response());\n        });\n\n        $kernel->terminateWithException(new \\Exception('boo'), $request = Request::create('/'));\n        $this->assertSame($request, $capturedRequest);\n        $this->assertNull($requestStack->getCurrentRequest());\n    }\n\n    public function testVerifyRequestStackPushPopDuringHandle()\n    {\n        $request = new Request();\n\n        $stack = $this->getMockBuilder(RequestStack::class)->onlyMethods(['push', 'pop'])->getMock();\n        $stack->expects($this->once())->method('push')->with($this->equalTo($request));\n        $stack->expects($this->once())->method('pop');\n\n        $dispatcher = new EventDispatcher();\n        $kernel = $this->getHttpKernel($dispatcher, null, $stack);\n\n        $kernel->handle($request, HttpKernelInterface::MAIN_REQUEST);\n    }\n\n    public function testVerifyRequestStackPushPopWithStreamedResponse()\n    {\n        $request = new Request();\n        $stack = new RequestStack();\n        $dispatcher = new EventDispatcher();\n        $kernel = $this->getHttpKernel($dispatcher, static fn () => new StreamedResponse(static function () use ($stack) {\n            echo $stack->getMainRequest()::class;\n        }), $stack);\n\n        $response = $kernel->handle($request, HttpKernelInterface::MAIN_REQUEST);\n        self::assertNull($stack->getMainRequest());\n        ob_start();\n        $response->send();\n        self::assertSame(Request::class, ob_get_clean());\n        self::assertNull($stack->getMainRequest());\n    }\n\n    public function testInconsistentClientIpsOnMainRequests()\n    {\n        $this->expectException(BadRequestHttpException::class);\n        $request = new Request();\n        $request->setTrustedProxies(['1.1.1.1'], Request::HEADER_X_FORWARDED_FOR | Request::HEADER_FORWARDED);\n        $request->server->set('REMOTE_ADDR', '1.1.1.1');\n        $request->headers->set('FORWARDED', 'for=2.2.2.2');\n        $request->headers->set('X_FORWARDED_FOR', '3.3.3.3');\n\n        $dispatcher = new EventDispatcher();\n        $dispatcher->addListener(KernelEvents::REQUEST, static function ($event) {\n            $event->getRequest()->getClientIp();\n        });\n\n        $kernel = $this->getHttpKernel($dispatcher);\n        $kernel->handle($request, $kernel::MAIN_REQUEST, false);\n\n        Request::setTrustedProxies([], -1);\n    }\n\n    public function testResponseEventCanAccessControllerAttributes()\n    {\n        $dispatcher = new EventDispatcher();\n        $capturedAttributes = null;\n\n        $dispatcher->addListener(KernelEvents::CONTROLLER, static function ($event) {\n            $event->setController($event->getController(), [new Bar('test')]);\n        });\n\n        $dispatcher->addListener(KernelEvents::RESPONSE, static function ($event) use (&$capturedAttributes) {\n            $capturedAttributes = $event->controllerMetadata->getAttributes('*');\n        });\n\n        $kernel = $this->getHttpKernel($dispatcher);\n\n        $kernel->handle(new Request(), HttpKernelInterface::MAIN_REQUEST, false);\n\n        $this->assertEquals([new Bar('test')], $capturedAttributes);\n    }\n\n    public function testViewEventProvidesControllerArgumentsViaMetadata()\n    {\n        $dispatcher = new EventDispatcher();\n        $capturedArguments = $capturedNamedArguments = null;\n\n        $dispatcher->addListener(KernelEvents::VIEW, static function ($event) use (&$capturedArguments, &$capturedNamedArguments) {\n            $capturedArguments = $event->controllerMetadata->getArguments();\n            $capturedNamedArguments = $event->controllerMetadata->getNamedArguments();\n            $event->setResponse(new Response('ok'));\n        });\n\n        $kernel = $this->getHttpKernel($dispatcher, static fn ($value) => $value, arguments: ['resolved']);\n\n        $kernel->handle(new Request(), HttpKernelInterface::MAIN_REQUEST, false);\n\n        $this->assertSame(['resolved'], $capturedArguments);\n        $this->assertSame(['value' => 'resolved'], $capturedNamedArguments);\n    }\n\n    public function testExceptionEventProvidesControllerMetadata()\n    {\n        $dispatcher = new EventDispatcher();\n        $capturedController = $capturedArguments = null;\n        $controller = static fn (string $value) => throw new \\RuntimeException('boom');\n\n        $dispatcher->addListener(KernelEvents::EXCEPTION, static function ($event) use (&$capturedController, &$capturedArguments) {\n            $capturedController = $event->controllerMetadata->getController();\n            $capturedArguments = $event->controllerMetadata->getArguments();\n            $event->setResponse(new Response('handled'));\n        });\n\n        $kernel = $this->getHttpKernel($dispatcher, $controller, arguments: ['meta']);\n\n        $response = $kernel->handle(new Request(), HttpKernelInterface::MAIN_REQUEST, true);\n\n        $this->assertSame('handled', $response->getContent());\n        $this->assertSame($controller, $capturedController);\n        $this->assertSame(['meta'], $capturedArguments);\n    }\n\n    public function testFinishRequestEventKeepsControllerMetadata()\n    {\n        $dispatcher = new EventDispatcher();\n        $capturedArguments = null;\n\n        $dispatcher->addListener(KernelEvents::FINISH_REQUEST, static function ($event) use (&$capturedArguments) {\n            $capturedArguments = $event->controllerMetadata->getArguments();\n        });\n\n        $kernel = $this->getHttpKernel($dispatcher, static fn ($value) => new Response($value), arguments: ['done']);\n\n        $response = $kernel->handle(new Request(), HttpKernelInterface::MAIN_REQUEST, false);\n\n        $this->assertSame('done', $response->getContent());\n        $this->assertSame(['done'], $capturedArguments);\n    }\n\n    private function getHttpKernel(EventDispatcherInterface $eventDispatcher, $controller = null, ?RequestStack $requestStack = null, array $arguments = [], bool $handleAllThrowables = false)\n    {\n        $controller ??= static fn () => new Response('Hello');\n\n        $controllerResolver = $this->createStub(ControllerResolverInterface::class);\n        $controllerResolver\n            ->method('getController')\n            ->willReturn($controller);\n\n        $argumentResolver = $this->createStub(ArgumentResolverInterface::class);\n        $argumentResolver\n            ->method('getArguments')\n            ->willReturn($arguments);\n\n        return new HttpKernel($eventDispatcher, $controllerResolver, $requestStack, $argumentResolver, $handleAllThrowables);\n    }\n\n    private function assertResponseEquals(Response $expected, Response $actual)\n    {\n        $expected->setDate($actual->getDate());\n        $this->assertEquals($expected, $actual);\n    }\n}\n\nclass TestController\n{\n    public function __invoke()\n    {\n        return new Response('foo');\n    }\n\n    public function controller()\n    {\n        return new Response('foo');\n    }\n\n    public static function staticController()\n    {\n        return new Response('foo');\n    }\n}\n\nfunction controller_func()\n{\n    return new Response('foo');\n}\n"
  },
  {
    "path": "Tests/KernelTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests;\n\nuse PHPUnit\\Framework\\Attributes\\Group;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Config\\Loader\\LoaderInterface;\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\ContainerInterface;\nuse Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\Filesystem\\Exception\\IOException;\nuse Symfony\\Component\\Filesystem\\Filesystem;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Bundle\\Bundle;\nuse Symfony\\Component\\HttpKernel\\Bundle\\BundleInterface;\nuse Symfony\\Component\\HttpKernel\\CacheWarmer\\WarmableInterface;\nuse Symfony\\Component\\HttpKernel\\DependencyInjection\\ResettableServicePass;\nuse Symfony\\Component\\HttpKernel\\DependencyInjection\\ServicesResetter;\nuse Symfony\\Component\\HttpKernel\\HttpKernel;\nuse Symfony\\Component\\HttpKernel\\HttpKernelInterface;\nuse Symfony\\Component\\HttpKernel\\Kernel;\nuse Symfony\\Component\\HttpKernel\\KernelInterface;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\KernelWithoutBundles;\nuse Symfony\\Component\\HttpKernel\\Tests\\Fixtures\\ResettableService;\n\nclass KernelTest extends TestCase\n{\n    protected function tearDown(): void\n    {\n        try {\n            (new Filesystem())->remove(__DIR__.'/Fixtures/var');\n        } catch (IOException $e) {\n        }\n    }\n\n    public function testConstructor()\n    {\n        $env = 'test_env';\n        $debug = true;\n        $kernel = new KernelForTest($env, $debug);\n\n        $this->assertEquals($env, $kernel->getEnvironment());\n        $this->assertEquals($debug, $kernel->isDebug());\n        $this->assertFalse($kernel->isBooted());\n        $this->assertLessThanOrEqual(microtime(true), $kernel->getStartTime());\n    }\n\n    public function testEmptyEnv()\n    {\n        $this->expectException(\\InvalidArgumentException::class);\n        $this->expectExceptionMessage(\\sprintf('Invalid environment provided to \"%s\": the environment cannot be empty.', KernelForTest::class));\n\n        new KernelForTest('', false);\n    }\n\n    public function testClone()\n    {\n        $env = 'test_env';\n        $debug = true;\n        $kernel = new KernelForTest($env, $debug);\n\n        $clone = clone $kernel;\n\n        $this->assertEquals($env, $clone->getEnvironment());\n        $this->assertEquals($debug, $clone->isDebug());\n        $this->assertFalse($clone->isBooted());\n        $this->assertLessThanOrEqual(microtime(true), $clone->getStartTime());\n    }\n\n    public function testClassNameValidityGetter()\n    {\n        $this->expectException(\\InvalidArgumentException::class);\n        $this->expectExceptionMessage('The environment \"test.env\" contains invalid characters, it can only contain characters allowed in PHP class names.');\n        // We check the classname that will be generated by using a $env that\n        // contains invalid characters.\n        $env = 'test.env';\n        $kernel = new KernelForTest($env, false, false);\n\n        $kernel->boot();\n    }\n\n    public function testInitializeContainerClearsOldContainers()\n    {\n        $fs = new Filesystem();\n        $legacyContainerDir = __DIR__.'/Fixtures/var/cache/custom/ContainerA123456';\n        $fs->mkdir($legacyContainerDir);\n        touch($legacyContainerDir.'.legacy');\n\n        $kernel = new CustomProjectDirKernel();\n        $kernel->boot();\n\n        $containerDir = __DIR__.'/Fixtures/var/cache/custom/'.substr($kernel->getContainer()::class, 0, 16);\n        $this->assertTrue(unlink(__DIR__.'/Fixtures/var/cache/custom/Symfony_Component_HttpKernel_Tests_CustomProjectDirKernelCustomDebugContainer.php.meta'));\n        $this->assertFileExists($containerDir);\n        $this->assertFileDoesNotExist($containerDir.'.legacy');\n\n        $kernel = new CustomProjectDirKernel(static function ($container) { $container->register('foo', 'stdClass')->setPublic(true); });\n        $kernel->boot();\n\n        $this->assertFileExists($containerDir);\n        $this->assertFileExists($containerDir.'.legacy');\n\n        $this->assertFileDoesNotExist($legacyContainerDir);\n        $this->assertFileDoesNotExist($legacyContainerDir.'.legacy');\n    }\n\n    public function testBootInitializesBundlesAndContainer()\n    {\n        $kernel = $this->getKernel(['initializeBundles']);\n        $kernel->expects($this->once())\n            ->method('initializeBundles');\n\n        $kernel->boot();\n    }\n\n    public function testBootSetsTheContainerToTheBundles()\n    {\n        $bundle = $this->createMock(Bundle::class);\n        $bundle->expects($this->once())\n            ->method('setContainer');\n\n        $kernel = $this->getKernel(['initializeBundles', 'getBundles']);\n        $kernel->expects($this->once())\n            ->method('getBundles')\n            ->willReturn([$bundle]);\n\n        $kernel->boot();\n    }\n\n    public function testBootSetsTheBootedFlagToTrue()\n    {\n        // use test kernel to access isBooted()\n        $kernel = new KernelForTest('test', false);\n        $kernel->boot();\n\n        $this->assertTrue($kernel->isBooted());\n    }\n\n    public function testClassCacheIsNotLoadedByDefault()\n    {\n        $kernel = $this->getKernel(['initializeBundles', 'doLoadClassCache'], [], false, KernelForTestWithLoadClassCache::class);\n        $kernel->expects($this->never())\n            ->method('doLoadClassCache');\n\n        $kernel->boot();\n    }\n\n    public function testBootKernelSeveralTimesOnlyInitializesBundlesOnce()\n    {\n        $kernel = $this->getKernel(['initializeBundles']);\n        $kernel->expects($this->once())\n            ->method('initializeBundles');\n\n        $kernel->boot();\n        $kernel->boot();\n    }\n\n    public function testShutdownCallsShutdownOnAllBundles()\n    {\n        $bundle = $this->createMock(Bundle::class);\n        $bundle->expects($this->once())\n            ->method('shutdown');\n\n        $kernel = new KernelForTest('test', false, true, [$bundle]);\n\n        $kernel->boot();\n        $kernel->shutdown();\n    }\n\n    public function testShutdownGivesNullContainerToAllBundles()\n    {\n        $bundle = $this->createMock(Bundle::class);\n        $bundle->expects($this->exactly(2))\n            ->method('setContainer')\n            ->willReturnCallback(function ($container) {\n                if (null !== $container) {\n                    $this->assertInstanceOf(ContainerInterface::class, $container);\n                }\n            })\n        ;\n\n        $kernel = new KernelForTest('test', false, true, [$bundle]);\n\n        $kernel->boot();\n        $kernel->shutdown();\n    }\n\n    public function testHandleCallsHandleOnHttpKernel()\n    {\n        $type = HttpKernelInterface::MAIN_REQUEST;\n        $catch = true;\n        $request = new Request();\n\n        $httpKernelMock = $this->getMockBuilder(HttpKernel::class)\n            ->disableOriginalConstructor()\n            ->getMock();\n        $httpKernelMock\n            ->expects($this->once())\n            ->method('handle')\n            ->with($request, $type, $catch);\n\n        $kernel = $this->getKernel(['getHttpKernel']);\n        $kernel->expects($this->once())\n            ->method('getHttpKernel')\n            ->willReturn($httpKernelMock);\n\n        $kernel->handle($request, $type, $catch);\n    }\n\n    public function testHandleBootsTheKernel()\n    {\n        $type = HttpKernelInterface::MAIN_REQUEST;\n        $catch = true;\n        $request = new Request();\n\n        $httpKernelMock = $this->createStub(HttpKernelInterface::class);\n\n        $kernel = $this->getKernel(['getHttpKernel', 'boot']);\n        $kernel->expects($this->once())\n            ->method('getHttpKernel')\n            ->willReturn($httpKernelMock);\n\n        $kernel->expects($this->once())\n            ->method('boot');\n\n        $kernel->handle($request, $type, $catch);\n    }\n\n    public function testSerialize()\n    {\n        $env = 'test_env';\n        $debug = true;\n        $kernel = new KernelForTest($env, $debug);\n        $expected = \\sprintf('O:48:\"%s\":2:{s:11:\"environment\";s:8:\"test_env\";s:5:\"debug\";b:1;}', KernelForTest::class);\n        $this->assertEquals($expected, serialize($kernel));\n    }\n\n    public function testLocateResourceThrowsExceptionWhenNameIsNotValid()\n    {\n        $this->expectException(\\InvalidArgumentException::class);\n        (new KernelForTest('test', false))->locateResource('Foo');\n    }\n\n    public function testLocateResourceThrowsExceptionWhenNameIsUnsafe()\n    {\n        $this->expectException(\\RuntimeException::class);\n        (new KernelForTest('test', false))->locateResource('@FooBundle/../bar');\n    }\n\n    public function testLocateResourceThrowsExceptionWhenBundleDoesNotExist()\n    {\n        $this->expectException(\\InvalidArgumentException::class);\n        (new KernelForTest('test', false))->locateResource('@FooBundle/config/routing.xml');\n    }\n\n    public function testLocateResourceThrowsExceptionWhenResourceDoesNotExist()\n    {\n        $bundle = $this->createStub(BundleInterface::class);\n        $bundle->method('getPath')->willReturn(__DIR__.'/Fixtures/Bundle1Bundle');\n        $this->expectException(\\InvalidArgumentException::class);\n        $kernel = $this->getKernel(['getBundle']);\n        $kernel\n            ->expects($this->once())\n            ->method('getBundle')\n            ->willReturn($bundle)\n        ;\n\n        $kernel->locateResource('@Bundle1Bundle/config/routing.xml');\n    }\n\n    public function testLocateResourceReturnsTheFirstThatMatches()\n    {\n        $bundle = $this->createStub(BundleInterface::class);\n        $bundle->method('getPath')->willReturn(__DIR__.'/Fixtures/Bundle1Bundle');\n        $kernel = $this->getKernel(['getBundle']);\n        $kernel\n            ->expects($this->once())\n            ->method('getBundle')\n            ->willReturn($bundle)\n        ;\n\n        $this->assertEquals(__DIR__.'/Fixtures/Bundle1Bundle/foo.txt', $kernel->locateResource('@Bundle1Bundle/foo.txt'));\n    }\n\n    public function testLocateResourceOnDirectories()\n    {\n        $bundle = $this->createStub(BundleInterface::class);\n        $bundle->method('getName')->willReturn('Bundle1Bundle');\n        $bundle->method('getPath')->willReturn(__DIR__.'/Fixtures/Bundle1Bundle');\n        $kernel = $this->getKernel(['getBundle']);\n        $kernel\n            ->expects($this->exactly(2))\n            ->method('getBundle')\n            ->willReturn($bundle)\n        ;\n\n        $this->assertEquals(\n            __DIR__.'/Fixtures/Bundle1Bundle/Resources/',\n            $kernel->locateResource('@Bundle1Bundle/Resources/')\n        );\n        $this->assertEquals(\n            __DIR__.'/Fixtures/Bundle1Bundle/Resources',\n            $kernel->locateResource('@Bundle1Bundle/Resources')\n        );\n    }\n\n    public function testInitializeBundleThrowsExceptionWhenRegisteringTwoBundlesWithTheSameName()\n    {\n        $this->expectException(\\LogicException::class);\n        $this->expectExceptionMessage('Trying to register two bundles with the same name \"DuplicateName\"');\n        $fooBundle = $this->createStub(BundleInterface::class);\n        $fooBundle->method('getName')->willReturn('DuplicateName');\n        $barBundle = $this->createStub(BundleInterface::class);\n        $barBundle->method('getName')->willReturn('DuplicateName');\n\n        $kernel = new KernelForTest('test', false, true, [$fooBundle, $barBundle]);\n        $kernel->boot();\n    }\n\n    public function testTerminateReturnsSilentlyIfKernelIsNotBooted()\n    {\n        $kernel = $this->getKernel(['getHttpKernel']);\n        $kernel->expects($this->never())\n            ->method('getHttpKernel');\n\n        $kernel->terminate(Request::create('/'), new Response());\n    }\n\n    public function testTerminateDelegatesTerminationOnlyForTerminableInterface()\n    {\n        // does not implement TerminableInterface\n        $httpKernel = new TestKernel();\n\n        $kernel = $this->getKernel(['getHttpKernel']);\n        $kernel->expects($this->once())\n            ->method('getHttpKernel')\n            ->willReturn($httpKernel);\n\n        $kernel->boot();\n        $kernel->terminate(Request::create('/'), new Response());\n\n        $this->assertFalse($httpKernel->terminateCalled, 'terminate() is never called if the kernel class does not implement TerminableInterface');\n\n        // implements TerminableInterface\n        $httpKernelMock = $this->getMockBuilder(HttpKernel::class)\n            ->disableOriginalConstructor()\n            ->onlyMethods(['terminate'])\n            ->getMock();\n\n        $httpKernelMock\n            ->expects($this->once())\n            ->method('terminate');\n\n        $kernel = $this->getKernel(['getHttpKernel']);\n        $kernel->expects($this->exactly(2))\n            ->method('getHttpKernel')\n            ->willReturn($httpKernelMock);\n\n        $kernel->boot();\n        $kernel->terminate(Request::create('/'), new Response());\n    }\n\n    public function testKernelWithoutBundles()\n    {\n        $kernel = new KernelWithoutBundles('test', true);\n        $kernel->boot();\n\n        $this->assertTrue($kernel->getContainer()->getParameter('test_executed'));\n    }\n\n    public function testProjectDirExtension()\n    {\n        $kernel = new CustomProjectDirKernel();\n        $kernel->boot();\n\n        $this->assertSame(__DIR__.'/Fixtures', $kernel->getProjectDir());\n        $this->assertSame(__DIR__.\\DIRECTORY_SEPARATOR.'Fixtures', $kernel->getContainer()->getParameter('kernel.project_dir'));\n    }\n\n    public function testKernelReset()\n    {\n        $this->tearDown();\n\n        $kernel = new CustomProjectDirKernel();\n        $kernel->boot();\n\n        $containerClass = $kernel->getContainer()::class;\n        $containerFile = (new \\ReflectionClass($kernel->getContainer()))->getFileName();\n        unlink(__DIR__.'/Fixtures/var/cache/custom/Symfony_Component_HttpKernel_Tests_CustomProjectDirKernelCustomDebugContainer.php.meta');\n\n        $kernel = new CustomProjectDirKernel();\n        $kernel->boot();\n\n        $this->assertInstanceOf($containerClass, $kernel->getContainer());\n        $this->assertFileExists($containerFile);\n        unlink(__DIR__.'/Fixtures/var/cache/custom/Symfony_Component_HttpKernel_Tests_CustomProjectDirKernelCustomDebugContainer.php.meta');\n\n        $kernel = new CustomProjectDirKernel(static function ($container) { $container->register('foo', 'stdClass')->setPublic(true); });\n        $kernel->boot();\n\n        $this->assertNotInstanceOf($containerClass, $kernel->getContainer());\n        $this->assertFileExists($containerFile);\n        $this->assertFileExists(\\dirname($containerFile).'.legacy');\n    }\n\n    public function testKernelExtension()\n    {\n        $kernel = new class extends CustomProjectDirKernel implements ExtensionInterface {\n            public function load(array $configs, ContainerBuilder $container): void\n            {\n                $container->setParameter('test.extension-registered', true);\n            }\n\n            /**\n             * To be removed when symfony/dependency-injection is bumped to 8.0+.\n             */\n            public function getNamespace(): string\n            {\n                return '';\n            }\n\n            /**\n             * To be removed when symfony/dependency-injection is bumped to 8.0+.\n             */\n            public function getXsdValidationBasePath(): string|false\n            {\n                return false;\n            }\n\n            public function getAlias(): string\n            {\n                return 'test-extension';\n            }\n        };\n        $kernel->boot();\n\n        $this->assertTrue($kernel->getContainer()->getParameter('test.extension-registered'));\n    }\n\n    public function testKernelPass()\n    {\n        $kernel = new PassKernel();\n        $kernel->boot();\n\n        $this->assertTrue($kernel->getContainer()->getParameter('test.processed'));\n    }\n\n    public function testWarmup()\n    {\n        $kernel = new CustomProjectDirKernel();\n        $kernel->boot();\n\n        $this->assertTrue($kernel->warmedUp);\n        $this->assertSame(realpath($kernel->getBuildDir()), $kernel->warmedUpBuildDir);\n    }\n\n    public function testServicesResetter()\n    {\n        $httpKernelMock = $this->getMockBuilder(HttpKernelInterface::class)\n            ->disableOriginalConstructor()\n            ->getMock();\n        $httpKernelMock\n            ->expects($this->exactly(2))\n            ->method('handle');\n\n        $kernel = new CustomProjectDirKernel(static function ($container) {\n            $container->addCompilerPass(new ResettableServicePass());\n            $container->register('one', ResettableService::class)\n                ->setPublic(true)\n                ->addTag('kernel.reset', ['method' => 'reset']);\n            $container->register('services_resetter', ServicesResetter::class)->setPublic(true);\n        }, $httpKernelMock, 'resetting');\n\n        ResettableService::$counter = 0;\n\n        $request = new Request();\n\n        $kernel->handle($request);\n        $kernel->getContainer()->get('one');\n\n        $this->assertEquals(0, ResettableService::$counter);\n        $this->assertFalse($kernel->getContainer()->initialized('services_resetter'));\n\n        $kernel->handle($request);\n\n        $this->assertEquals(1, ResettableService::$counter);\n    }\n\n    public function testServicesAreNotResetBetweenHttpCacheFragments()\n    {\n        ResettableService::$counter = 0;\n        $fragmentKernel = new FragmentHandlingKernel();\n\n        $kernel = new CustomProjectDirKernel(static function (ContainerBuilder $container) {\n            $container->addCompilerPass(new ResettableServicePass());\n            $container->register('kernel', CustomProjectDirKernel::class)\n                ->setSynthetic(true)\n                ->setPublic(true);\n            $container->register('one', ResettableService::class)\n                ->setPublic(true)\n                ->addTag('kernel.reset', ['method' => 'reset']);\n            $container->register('services_resetter', ServicesResetter::class)->setPublic(true);\n            $container->register('http_cache', FragmentRenderingHttpCache::class)\n                ->setPublic(true)\n                ->addArgument(new Reference('kernel'));\n        }, $fragmentKernel, 'http_cache_fragments');\n\n        $kernel->handle(new Request());\n\n        $this->assertSame([\n            ['/first-fragment', HttpKernelInterface::MAIN_REQUEST],\n            ['/second-fragment', HttpKernelInterface::MAIN_REQUEST],\n        ], $fragmentKernel->handledPaths);\n        $this->assertSame([0, 0], $fragmentKernel->resetCounters);\n        $this->assertSame(0, ResettableService::$counter);\n\n        $kernel->boot();\n\n        $this->assertSame(1, ResettableService::$counter);\n    }\n\n    public function testHttpCacheHandlesRequestsAfterKernelBoot()\n    {\n        $kernel = new CustomProjectDirKernel(static function (ContainerBuilder $container) {\n            $container->register('http_cache', RecordingHttpCache::class)\n                ->setPublic(true);\n        }, new ThrowingHttpKernel(), 'http_cache_worker');\n\n        $kernel->boot();\n\n        $firstResponse = $kernel->handle(Request::create('/worker-first'));\n        $secondResponse = $kernel->handle(Request::create('/worker-second'));\n\n        /** @var RecordingHttpCache $httpCache */\n        $httpCache = $kernel->getContainer()->get('http_cache');\n\n        $this->assertSame([\n            ['/worker-first', HttpKernelInterface::MAIN_REQUEST],\n            ['/worker-second', HttpKernelInterface::MAIN_REQUEST],\n        ], $httpCache->handledPaths);\n        $this->assertSame('cached: /worker-first', $firstResponse->getContent());\n        $this->assertSame('cached: /worker-second', $secondResponse->getContent());\n    }\n\n    #[Group('time-sensitive')]\n    public function testKernelStartTimeIsResetWhileBootingAlreadyBootedKernel()\n    {\n        $kernel = new KernelForTest('test', true);\n        $kernel->boot();\n        $preReBoot = $kernel->getStartTime();\n\n        sleep(3600); // Intentionally large value to detect if ClockMock ever breaks\n        $kernel->reboot(null);\n\n        $this->assertGreaterThan($preReBoot, $kernel->getStartTime());\n    }\n\n    public function testAnonymousKernelGeneratesValidContainerClass()\n    {\n        $kernel = new class('test', true) extends Kernel {\n            public function registerBundles(): iterable\n            {\n                return [];\n            }\n\n            public function registerContainerConfiguration(LoaderInterface $loader): void\n            {\n            }\n\n            public function getContainerClass(): string\n            {\n                return parent::getContainerClass();\n            }\n        };\n\n        $this->assertMatchesRegularExpression('/^[a-zA-Z_\\x80-\\xff][a-zA-Z0-9_\\x80-\\xff]*TestDebugContainer$/', $kernel->getContainerClass());\n    }\n\n    public function testTrustedParameters()\n    {\n        $kernel = new CustomProjectDirKernel(static function (ContainerBuilder $container) {\n            $container->setParameter('kernel.trusted_hosts', '^a{2,3}.com$, ^b{2,}.com$');\n            $container->setParameter('kernel.trusted_proxies', 'a,b');\n            $container->setParameter('kernel.trusted_headers', 'x-forwarded-for');\n        });\n        $kernel->boot();\n\n        try {\n            $this->assertSame(['{^a{2,3}.com$}i', '{^b{2,}.com$}i'], Request::getTrustedHosts());\n            $this->assertSame(['a', 'b'], Request::getTrustedProxies());\n            $this->assertSame(Request::HEADER_X_FORWARDED_FOR, Request::getTrustedHeaderSet());\n        } finally {\n            Request::setTrustedHosts([]);\n            Request::setTrustedProxies([], 0);\n        }\n    }\n\n    public function testSourceDateEpoch()\n    {\n        $sourceDateEpoch = 1609459200; // 2021-01-01 00:00:00 UTC\n\n        $_SERVER['SOURCE_DATE_EPOCH'] = $sourceDateEpoch;\n\n        $kernel = new class('test', true) extends Kernel {\n            public function registerBundles(): iterable\n            {\n                return [];\n            }\n\n            public function registerContainerConfiguration(LoaderInterface $loader): void\n            {\n            }\n\n            public function getProjectDir(): string\n            {\n                return __DIR__.'/Fixtures';\n            }\n        };\n\n        $kernel->boot();\n        $container = $kernel->getContainer();\n\n        $this->assertSame($sourceDateEpoch, $container->getParameter('container.build_time'));\n    }\n\n    public function testSourceDateEpochWithKernelContainerBuildTime()\n    {\n        $sourceDateEpoch = 1609459200; // 2021-01-01 00:00:00 UTC\n        $kernelBuildTime = 1609545600; // 2021-01-02 00:00:00 UTC\n\n        $_SERVER['SOURCE_DATE_EPOCH'] = $sourceDateEpoch;\n\n        $kernel = new CustomProjectDirKernel(static function (ContainerBuilder $container) use ($kernelBuildTime) {\n            $container->setParameter('kernel.container_build_time', $kernelBuildTime);\n        });\n        $kernel->boot();\n        $container = $kernel->getContainer();\n\n        // kernel.container_build_time should take precedence over SOURCE_DATE_EPOCH\n        $this->assertSame($kernelBuildTime, $container->getParameter('container.build_time'));\n    }\n\n    /**\n     * Returns a mock for the abstract kernel.\n     *\n     * @param array $methods Additional methods to mock (besides the abstract ones)\n     * @param array $bundles Bundles to register\n     */\n    protected function getKernel(array $methods = [], array $bundles = [], bool $debug = false, string $kernelClass = KernelForTest::class): Kernel\n    {\n        $methods[] = 'registerBundles';\n\n        $kernelMockBuilder = $this\n            ->getMockBuilder($kernelClass)\n            ->onlyMethods($methods)\n            ->setConstructorArgs(['test', $debug])\n        ;\n\n        $kernel = $kernelMockBuilder->getMock();\n        $kernel\n            ->method('registerBundles')\n            ->willReturn($bundles)\n        ;\n\n        return $kernel;\n    }\n}\n\nclass TestKernel implements HttpKernelInterface\n{\n    public bool $terminateCalled = false;\n\n    public function terminate(): void\n    {\n        $this->terminateCalled = true;\n    }\n\n    public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true): Response\n    {\n    }\n\n    public function getProjectDir(): string\n    {\n        return __DIR__.'/Fixtures';\n    }\n}\n\nclass CustomProjectDirKernel extends Kernel implements WarmableInterface\n{\n    public bool $warmedUp = false;\n\n    public ?string $warmedUpBuildDir = null;\n\n    public function __construct(\n        private readonly ?\\Closure $buildContainer = null,\n        private readonly ?HttpKernelInterface $httpKernel = null,\n        $env = 'custom',\n    ) {\n        parent::__construct($env, true);\n    }\n\n    public function registerBundles(): iterable\n    {\n        return [];\n    }\n\n    public function registerContainerConfiguration(LoaderInterface $loader): void\n    {\n    }\n\n    public function getProjectDir(): string\n    {\n        return __DIR__.'/Fixtures';\n    }\n\n    public function warmUp(string $cacheDir, ?string $buildDir = null): array\n    {\n        $this->warmedUp = true;\n        $this->warmedUpBuildDir = $buildDir;\n\n        return [];\n    }\n\n    protected function build(ContainerBuilder $container): void\n    {\n        if ($build = $this->buildContainer) {\n            $build($container);\n        }\n    }\n\n    protected function getHttpKernel(): HttpKernelInterface\n    {\n        return $this->httpKernel;\n    }\n}\n\nclass PassKernel extends CustomProjectDirKernel implements CompilerPassInterface\n{\n    public function __construct()\n    {\n        parent::__construct();\n        Kernel::__construct('pass', true);\n    }\n\n    public function process(ContainerBuilder $container): void\n    {\n        $container->setParameter('test.processed', true);\n    }\n}\n\nclass FragmentHandlingKernel implements HttpKernelInterface\n{\n    public array $handledPaths = [];\n    public array $resetCounters = [];\n\n    public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true): Response\n    {\n        $this->handledPaths[] = [$request->getPathInfo(), $type];\n        $this->resetCounters[] = ResettableService::$counter;\n\n        return new Response($request->getPathInfo());\n    }\n}\n\nclass FragmentRenderingHttpCache implements HttpKernelInterface\n{\n    public function __construct(\n        private KernelInterface $kernel,\n        private string $trackedServiceId = 'one',\n    ) {\n    }\n\n    public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true): Response\n    {\n        $this->kernel->boot();\n        $this->kernel->getContainer()->get($this->trackedServiceId);\n\n        $responses = [];\n        foreach (['/first-fragment', '/second-fragment'] as $path) {\n            $responses[] = $this->kernel->handle(Request::create($path), self::MAIN_REQUEST, $catch);\n        }\n\n        return new Response(implode('', array_map(static fn (Response $response) => $response->getContent(), $responses)));\n    }\n}\n\nclass RecordingHttpCache implements HttpKernelInterface\n{\n    public array $handledPaths = [];\n\n    public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true): Response\n    {\n        $this->handledPaths[] = [$request->getPathInfo(), $type];\n\n        return new Response('cached: '.$request->getPathInfo());\n    }\n}\n\nclass ThrowingHttpKernel implements HttpKernelInterface\n{\n    public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true): Response\n    {\n        throw new \\LogicException('The worker HTTP kernel should not be reached when the http_cache service handles the request.');\n    }\n}\n\nclass KernelForTest extends Kernel\n{\n    public function __construct(\n        string $environment,\n        bool $debug,\n        private readonly bool $fakeContainer = true,\n        private array $registeredBundles = [],\n    ) {\n        parent::__construct($environment, $debug);\n    }\n\n    public function getBundleMap(): array\n    {\n        return [];\n    }\n\n    public function registerBundles(): iterable\n    {\n        return $this->registeredBundles;\n    }\n\n    public function registerContainerConfiguration(LoaderInterface $loader): void\n    {\n    }\n\n    public function isBooted(): bool\n    {\n        return $this->booted;\n    }\n\n    public function getProjectDir(): string\n    {\n        return __DIR__;\n    }\n\n    protected function initializeContainer(): void\n    {\n        if ($this->fakeContainer) {\n            $this->container = new ContainerBuilder();\n        } else {\n            parent::initializeContainer();\n        }\n    }\n}\n\nclass KernelForTestWithLoadClassCache extends KernelForTest\n{\n    public function doLoadClassCache(): void\n    {\n    }\n}\n"
  },
  {
    "path": "Tests/Log/LoggerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Log;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\InvalidArgumentException;\nuse Psr\\Log\\LoggerInterface;\nuse Psr\\Log\\LogLevel;\nuse Symfony\\Component\\HttpKernel\\Log\\Logger;\n\n/**\n * @author Kévin Dunglas <dunglas@gmail.com>\n * @author Jordi Boggiano <j.boggiano@seld.be>\n */\nclass LoggerTest extends TestCase\n{\n    private Logger $logger;\n    private string $tmpFile;\n\n    protected function setUp(): void\n    {\n        $this->tmpFile = tempnam(sys_get_temp_dir(), 'log');\n        $this->logger = new Logger(LogLevel::DEBUG, $this->tmpFile);\n    }\n\n    protected function tearDown(): void\n    {\n        if (!@unlink($this->tmpFile)) {\n            file_put_contents($this->tmpFile, '');\n        }\n    }\n\n    public static function assertLogsMatch(array $expected, array $given)\n    {\n        foreach ($given as $k => $line) {\n            self::assertSame(1, preg_match('/[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}[\\+-][0-9]{2}:[0-9]{2} '.preg_quote($expected[$k]).'/', $line), \"\\\"$line\\\" do not match expected pattern \\\"$expected[$k]\\\"\");\n        }\n    }\n\n    /**\n     * Return the log messages in order.\n     *\n     * @return string[]\n     */\n    public function getLogs(): array\n    {\n        return file($this->tmpFile, \\FILE_IGNORE_NEW_LINES);\n    }\n\n    public function testImplements()\n    {\n        $this->assertInstanceOf(LoggerInterface::class, $this->logger);\n    }\n\n    #[DataProvider('provideLevelsAndMessages')]\n    public function testLogsAtAllLevels($level, $message)\n    {\n        $this->logger->{$level}($message, ['user' => 'Bob']);\n        $this->logger->log($level, $message, ['user' => 'Bob']);\n\n        $expected = [\n            \"[$level] message of level $level with context: Bob\",\n            \"[$level] message of level $level with context: Bob\",\n        ];\n        $this->assertLogsMatch($expected, $this->getLogs());\n    }\n\n    public static function provideLevelsAndMessages()\n    {\n        return [\n            LogLevel::EMERGENCY => [LogLevel::EMERGENCY, 'message of level emergency with context: {user}'],\n            LogLevel::ALERT => [LogLevel::ALERT, 'message of level alert with context: {user}'],\n            LogLevel::CRITICAL => [LogLevel::CRITICAL, 'message of level critical with context: {user}'],\n            LogLevel::ERROR => [LogLevel::ERROR, 'message of level error with context: {user}'],\n            LogLevel::WARNING => [LogLevel::WARNING, 'message of level warning with context: {user}'],\n            LogLevel::NOTICE => [LogLevel::NOTICE, 'message of level notice with context: {user}'],\n            LogLevel::INFO => [LogLevel::INFO, 'message of level info with context: {user}'],\n            LogLevel::DEBUG => [LogLevel::DEBUG, 'message of level debug with context: {user}'],\n        ];\n    }\n\n    public function testLogLevelDisabled()\n    {\n        $this->logger = new Logger(LogLevel::INFO, $this->tmpFile);\n\n        $this->logger->debug('test', ['user' => 'Bob']);\n        $this->logger->log(LogLevel::DEBUG, 'test', ['user' => 'Bob']);\n\n        // Will always be true, but asserts than an exception isn't thrown\n        $this->assertSame([], $this->getLogs());\n    }\n\n    public function testThrowsOnInvalidLevel()\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $this->logger->log('invalid level', 'Foo');\n    }\n\n    public function testThrowsOnInvalidMinLevel()\n    {\n        $this->expectException(InvalidArgumentException::class);\n        new Logger('invalid');\n    }\n\n    public function testInvalidOutput()\n    {\n        $this->expectException(InvalidArgumentException::class);\n        new Logger(LogLevel::DEBUG, '/');\n    }\n\n    public function testContextReplacement()\n    {\n        $logger = $this->logger;\n        $logger->info('{Message {nothing} {user} {foo.bar} a}', ['user' => 'Bob', 'foo.bar' => 'Bar']);\n\n        $expected = ['[info] {Message {nothing} Bob Bar a}'];\n        $this->assertLogsMatch($expected, $this->getLogs());\n    }\n\n    public function testObjectCastToString()\n    {\n        $dummy = $this->createPartialMock(DummyTest::class, ['__toString']);\n        $dummy->expects($this->atLeastOnce())\n            ->method('__toString')\n            ->willReturn('DUMMY');\n\n        $this->logger->warning($dummy);\n\n        $expected = ['[warning] DUMMY'];\n        $this->assertLogsMatch($expected, $this->getLogs());\n    }\n\n    public function testContextCanContainAnything()\n    {\n        $context = [\n            'bool' => true,\n            'null' => null,\n            'string' => 'Foo',\n            'int' => 0,\n            'float' => 0.5,\n            'nested' => ['with object' => new DummyTest()],\n            'object' => new \\DateTimeImmutable(),\n            'resource' => fopen('php://memory', 'r'),\n        ];\n\n        $this->logger->warning('Crazy context data', $context);\n\n        $expected = ['[warning] Crazy context data'];\n        $this->assertLogsMatch($expected, $this->getLogs());\n    }\n\n    public function testContextExceptionKeyCanBeExceptionOrOtherValues()\n    {\n        $logger = $this->logger;\n        $logger->warning('Random message', ['exception' => 'oops']);\n        $logger->critical('Uncaught Exception!', ['exception' => new \\LogicException('Fail')]);\n\n        $expected = [\n            '[warning] Random message',\n            '[critical] Uncaught Exception!',\n        ];\n        $this->assertLogsMatch($expected, $this->getLogs());\n    }\n\n    public function testFormatter()\n    {\n        $this->logger = new Logger(LogLevel::DEBUG, $this->tmpFile, static fn ($level, $message, $context) => json_encode(['level' => $level, 'message' => $message, 'context' => $context]));\n\n        $this->logger->error('An error', ['foo' => 'bar']);\n        $this->logger->warning('A warning', ['baz' => 'bar']);\n        $this->assertSame([\n            '{\"level\":\"error\",\"message\":\"An error\",\"context\":{\"foo\":\"bar\"}}',\n            '{\"level\":\"warning\",\"message\":\"A warning\",\"context\":{\"baz\":\"bar\"}}',\n        ], $this->getLogs());\n    }\n\n    public function testLogsWithoutOutput()\n    {\n        $oldErrorLog = ini_set('error_log', $this->tmpFile);\n\n        $logger = new Logger();\n        $logger->error('test');\n        $logger->critical('test');\n\n        $expected = [\n            '[error] test',\n            '[critical] test',\n        ];\n\n        foreach ($this->getLogs() as $k => $line) {\n            $this->assertSame(1, preg_match('/\\[[\\w\\/\\-: ]+\\] '.preg_quote($expected[$k]).'/', $line), \"\\\"$line\\\" do not match expected pattern \\\"$expected[$k]\\\"\");\n        }\n\n        ini_set('error_log', $oldErrorLog);\n    }\n}\n\nclass DummyTest\n{\n    public function __toString(): string\n    {\n    }\n}\n"
  },
  {
    "path": "Tests/Logger.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests;\n\nuse Psr\\Log\\AbstractLogger;\n\nclass Logger extends AbstractLogger\n{\n    protected array $logs;\n\n    public function __construct()\n    {\n        $this->clear();\n    }\n\n    public function getLogsForLevel(string $level): array\n    {\n        return $this->logs[$level];\n    }\n\n    public function clear(): void\n    {\n        $this->logs = [\n            'emergency' => [],\n            'alert' => [],\n            'critical' => [],\n            'error' => [],\n            'warning' => [],\n            'notice' => [],\n            'info' => [],\n            'debug' => [],\n        ];\n    }\n\n    public function log($level, $message, array $context = []): void\n    {\n        $this->logs[$level][] = $message;\n    }\n}\n"
  },
  {
    "path": "Tests/Profiler/FileProfilerStorageTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Profiler;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpKernel\\Profiler\\FileProfilerStorage;\nuse Symfony\\Component\\HttpKernel\\Profiler\\Profile;\n\nclass FileProfilerStorageTest extends TestCase\n{\n    private string $tmpDir;\n    private FileProfilerStorage $storage;\n\n    protected function setUp(): void\n    {\n        $this->tmpDir = sys_get_temp_dir().'/sf_profiler_file_storage';\n        if (is_dir($this->tmpDir)) {\n            self::cleanDir();\n        }\n        $this->storage = new FileProfilerStorage('file:'.$this->tmpDir);\n        $this->storage->purge();\n    }\n\n    protected function tearDown(): void\n    {\n        self::cleanDir();\n    }\n\n    public function testStore()\n    {\n        for ($i = 0; $i < 10; ++$i) {\n            $profile = new Profile('token_'.$i);\n            $profile->setIp('127.0.0.1');\n            $profile->setUrl('http://foo.bar');\n            $profile->setMethod('GET');\n            $this->storage->write($profile);\n        }\n        $this->assertCount(10, $this->storage->find('127.0.0.1', 'http://foo.bar', 20, 'GET'), '->write() stores data in the storage');\n    }\n\n    public function testChildren()\n    {\n        $parentProfile = new Profile('token_parent');\n        $parentProfile->setIp('127.0.0.1');\n        $parentProfile->setUrl('http://foo.bar/parent');\n        $parentProfile->setStatusCode(200);\n        $parentProfile->setMethod('GET');\n\n        $childProfile = new Profile('token_child');\n        $childProfile->setIp('127.0.0.1');\n        $childProfile->setUrl('http://foo.bar/child');\n        $childProfile->setStatusCode(200);\n        $childProfile->setMethod('GET');\n\n        $parentProfile->addChild($childProfile);\n\n        $this->storage->write($parentProfile);\n        $this->storage->write($childProfile);\n\n        // Load them from storage\n        $parentProfile = $this->storage->read('token_parent');\n        $childProfile = $this->storage->read('token_child');\n\n        // Check child has link to parent\n        $this->assertNotNull($childProfile->getParent());\n        $this->assertEquals($parentProfile->getToken(), $childProfile->getParentToken());\n\n        // Check parent has child\n        $children = $parentProfile->getChildren();\n        $this->assertCount(1, $children);\n        $this->assertEquals($childProfile->getToken(), $children[0]->getToken());\n    }\n\n    public function testStoreSpecialCharsInUrl()\n    {\n        // The storage accepts special characters in URLs (Even though URLs are not\n        // supposed to contain them)\n        $profile = new Profile('simple_quote');\n        $profile->setUrl('http://foo.bar/\\'');\n        $profile->setIp('127.0.0.1');\n        $profile->setStatusCode(200);\n        $profile->setMethod('GET');\n\n        $this->storage->write($profile);\n        $this->assertNotFalse($this->storage->read('simple_quote'), '->write() accepts single quotes in URL');\n\n        $profile = new Profile('double_quote');\n        $profile->setUrl('http://foo.bar/\"');\n        $profile->setIp('127.0.0.1');\n        $profile->setStatusCode(200);\n        $profile->setMethod('GET');\n\n        $this->storage->write($profile);\n        $this->assertNotFalse($this->storage->read('double_quote'), '->write() accepts double quotes in URL');\n\n        $profile = new Profile('backslash');\n        $profile->setUrl('http://foo.bar/\\\\');\n        $profile->setIp('127.0.0.1');\n        $profile->setStatusCode(200);\n        $profile->setMethod('GET');\n\n        $this->storage->write($profile);\n        $this->assertNotFalse($this->storage->read('backslash'), '->write() accepts backslash in URL');\n\n        $profile = new Profile('comma');\n        $profile->setUrl('http://foo.bar/,');\n        $profile->setIp('127.0.0.1');\n        $profile->setStatusCode(200);\n        $profile->setMethod('GET');\n\n        $this->storage->write($profile);\n        $this->assertNotFalse($this->storage->read('comma'), '->write() accepts comma in URL');\n    }\n\n    public function testStoreDuplicateToken()\n    {\n        $profile = new Profile('token');\n        $profile->setUrl('http://example.com/');\n        $profile->setIp('127.0.0.1');\n        $profile->setStatusCode(200);\n        $profile->setMethod('GET');\n\n        $this->assertTrue($this->storage->write($profile), '->write() returns true when the token is unique');\n\n        $profile->setUrl('http://example.net/');\n\n        $this->assertTrue($this->storage->write($profile), '->write() returns true when the token is already present in the storage');\n        $this->assertEquals('http://example.net/', $this->storage->read('token')->getUrl(), '->write() overwrites the current profile data');\n\n        $this->assertCount(1, $this->storage->find('', '', 1000, ''), '->find() does not return the same profile twice');\n    }\n\n    public function testRetrieveByIp()\n    {\n        $profile = new Profile('token');\n        $profile->setIp('127.0.0.1');\n        $profile->setMethod('GET');\n        $this->storage->write($profile);\n\n        $this->assertCount(1, $this->storage->find('127.0.0.1', '', 10, 'GET'), '->find() retrieve a record by IP');\n        $this->assertCount(0, $this->storage->find('127.0.%.1', '', 10, 'GET'), '->find() does not interpret a \"%\" as a wildcard in the IP');\n        $this->assertCount(0, $this->storage->find('127.0._.1', '', 10, 'GET'), '->find() does not interpret a \"_\" as a wildcard in the IP');\n    }\n\n    public function testRetrieveByStatusCode()\n    {\n        $profile200 = new Profile('statuscode200');\n        $profile200->setStatusCode(200);\n        $this->storage->write($profile200);\n\n        $profile404 = new Profile('statuscode404');\n        $profile404->setStatusCode(404);\n        $this->storage->write($profile404);\n\n        $this->assertCount(1, $this->storage->find(null, null, 10, null, null, null, '200'), '->find() retrieve a record by Status code 200');\n        $this->assertCount(1, $this->storage->find(null, null, 10, null, null, null, '404'), '->find() retrieve a record by Status code 404');\n    }\n\n    public function testRetrieveByUrl()\n    {\n        $profile = new Profile('simple_quote');\n        $profile->setIp('127.0.0.1');\n        $profile->setUrl('http://foo.bar/\\'');\n        $profile->setMethod('GET');\n        $this->storage->write($profile);\n\n        $profile = new Profile('double_quote');\n        $profile->setIp('127.0.0.1');\n        $profile->setUrl('http://foo.bar/\"');\n        $profile->setMethod('GET');\n        $this->storage->write($profile);\n\n        $profile = new Profile('backslash');\n        $profile->setIp('127.0.0.1');\n        $profile->setUrl('http://foo\\\\bar/');\n        $profile->setMethod('GET');\n        $this->storage->write($profile);\n\n        $profile = new Profile('percent');\n        $profile->setIp('127.0.0.1');\n        $profile->setUrl('http://foo.bar/%');\n        $profile->setMethod('GET');\n        $this->storage->write($profile);\n\n        $profile = new Profile('underscore');\n        $profile->setIp('127.0.0.1');\n        $profile->setUrl('http://foo.bar/_');\n        $profile->setMethod('GET');\n        $this->storage->write($profile);\n\n        $profile = new Profile('semicolon');\n        $profile->setIp('127.0.0.1');\n        $profile->setUrl('http://foo.bar/;');\n        $profile->setMethod('GET');\n        $this->storage->write($profile);\n\n        $profile = new Profile('webp');\n        $profile->setIp('127.0.0.1');\n        $profile->setUrl('http://foo.bar/img.webp');\n        $profile->setMethod('GET');\n        $this->storage->write($profile);\n\n        $this->assertCount(1, $this->storage->find('127.0.0.1', 'http://foo.bar/\\'', 10, 'GET'), '->find() accepts single quotes in URLs');\n        $this->assertCount(1, $this->storage->find('127.0.0.1', 'http://foo.bar/\"', 10, 'GET'), '->find() accepts double quotes in URLs');\n        $this->assertCount(1, $this->storage->find('127.0.0.1', 'http://foo\\\\bar/', 10, 'GET'), '->find() accepts backslash in URLs');\n        $this->assertCount(1, $this->storage->find('127.0.0.1', 'http://foo.bar/;', 10, 'GET'), '->find() accepts semicolon in URLs');\n        $this->assertCount(1, $this->storage->find('127.0.0.1', 'http://foo.bar/%', 10, 'GET'), '->find() does not interpret a \"%\" as a wildcard in the URL');\n        $this->assertCount(1, $this->storage->find('127.0.0.1', 'http://foo.bar/_', 10, 'GET'), '->find() does not interpret a \"_\" as a wildcard in the URL');\n        $this->assertCount(6, $this->storage->find('127.0.0.1', '!.webp', 10, 'GET'), '->find() does not interpret a \"!\" at the beginning as a negation operator in the URL');\n    }\n\n    public function testStoreTime()\n    {\n        $start = $now = time();\n\n        for ($i = 0; $i < 3; ++$i) {\n            $now += 60;\n            $profile = new Profile('time_'.$i);\n            $profile->setIp('127.0.0.1');\n            $profile->setUrl('http://foo.bar');\n            $profile->setTime($now);\n            $profile->setMethod('GET');\n            $this->storage->write($profile);\n        }\n\n        $records = $this->storage->find('', '', 3, 'GET', $start, $start + 3 * 60);\n        $this->assertCount(3, $records, '->find() returns all previously added records');\n        $this->assertEquals('time_2', $records[0]['token'], '->find() returns records ordered by time in descendant order');\n        $this->assertEquals('time_1', $records[1]['token'], '->find() returns records ordered by time in descendant order');\n        $this->assertEquals('time_0', $records[2]['token'], '->find() returns records ordered by time in descendant order');\n\n        $records = $this->storage->find('', '', 3, 'GET', $start, $start + 2 * 60);\n        $this->assertCount(2, $records, '->find() should return only first two of the previously added records');\n    }\n\n    public function testRetrieveByEmptyUrlAndIp()\n    {\n        for ($i = 0; $i < 5; ++$i) {\n            $profile = new Profile('token_'.$i);\n            $profile->setMethod('GET');\n            $this->storage->write($profile);\n        }\n        $this->assertCount(5, $this->storage->find('', '', 10, 'GET'), '->find() returns all previously added records');\n        $this->storage->purge();\n    }\n\n    public function testRetrieveByMethodAndLimit()\n    {\n        foreach (['POST', 'GET'] as $method) {\n            for ($i = 0; $i < 5; ++$i) {\n                $profile = new Profile('token_'.$i.$method);\n                $profile->setMethod($method);\n                $this->storage->write($profile);\n            }\n        }\n\n        $this->assertCount(5, $this->storage->find('', '', 5, 'POST'));\n\n        $this->storage->purge();\n    }\n\n    public function testPurge()\n    {\n        $profile = new Profile('token1');\n        $profile->setIp('127.0.0.1');\n        $profile->setUrl('http://example.com/');\n        $profile->setMethod('GET');\n        $profile->setStatusCode(200);\n        $this->storage->write($profile);\n\n        $this->assertNotFalse($this->storage->read('token1'));\n        $this->assertCount(1, $this->storage->find('127.0.0.1', '', 10, 'GET'));\n\n        $profile = new Profile('token2');\n        $profile->setIp('127.0.0.1');\n        $profile->setUrl('http://example.net/');\n        $profile->setMethod('GET');\n        $profile->setStatusCode(200);\n        $this->storage->write($profile);\n\n        $this->assertNotFalse($this->storage->read('token2'));\n        $this->assertCount(2, $this->storage->find('127.0.0.1', '', 10, 'GET'));\n\n        $this->storage->purge();\n\n        $this->assertNull($this->storage->read('token'), '->purge() removes all data stored by profiler');\n        $this->assertCount(0, $this->storage->find('127.0.0.1', '', 10, 'GET'), '->purge() removes all items from index');\n    }\n\n    public function testDuplicates()\n    {\n        for ($i = 1; $i <= 5; ++$i) {\n            $profile = new Profile('foo'.$i);\n            $profile->setIp('127.0.0.1');\n            $profile->setUrl('http://example.net/');\n            $profile->setMethod('GET');\n\n            // three duplicates\n            $this->storage->write($profile);\n            $this->storage->write($profile);\n            $this->storage->write($profile);\n        }\n        $this->assertCount(3, $this->storage->find('127.0.0.1', 'http://example.net/', 3, 'GET'), '->find() method returns incorrect number of entries');\n    }\n\n    public function testStatusCode()\n    {\n        $profile = new Profile('token1');\n        $profile->setStatusCode(200);\n        $this->storage->write($profile);\n\n        $profile = new Profile('token2');\n        $profile->setStatusCode(404);\n        $this->storage->write($profile);\n\n        $tokens = $this->storage->find('', '', 10, '');\n        $this->assertCount(2, $tokens);\n        $this->assertContains((int) $tokens[0]['status_code'], [200, 404]);\n        $this->assertContains((int) $tokens[1]['status_code'], [200, 404]);\n    }\n\n    public function testHasErrors()\n    {\n        $profile = new Profile('token_with_errors');\n        $profile->setIp('127.0.0.1');\n        $profile->setUrl('http://foo.bar/error');\n        $profile->setMethod('GET');\n        $profile->setStatusCode(500);\n        $profile->setHasErrors(true);\n        $this->storage->write($profile);\n\n        $profile = new Profile('token_without_errors');\n        $profile->setIp('127.0.0.1');\n        $profile->setUrl('http://foo.bar/success');\n        $profile->setMethod('GET');\n        $profile->setStatusCode(200);\n        $profile->setHasErrors(false);\n        $this->storage->write($profile);\n\n        $loadedProfile = $this->storage->read('token_with_errors');\n        $this->assertTrue($loadedProfile->hasErrors(), '->read() restores hasErrors=true on the Profile object');\n\n        $loadedProfile = $this->storage->read('token_without_errors');\n        $this->assertFalse($loadedProfile->hasErrors(), '->read() restores hasErrors=false on the Profile object');\n    }\n\n    public function testHasErrorsBackwardCompatibility()\n    {\n        // Test backward compatibility with old CSV lines that don't have has_errors field\n        $file = $this->tmpDir.'/index.csv';\n        $time = time();\n\n        // Write an old-format CSV line (8 fields, no has_errors)\n        file_put_contents($file, \"old_token,127.0.0.1,GET,http://foo.bar/old,{$time},,200,request\\n\");\n\n        $tokens = $this->storage->find('', '', 10, '');\n        $this->assertCount(1, $tokens);\n        $this->assertFalse($tokens[0]['has_errors'], '->find() returns has_errors=false for old CSV lines without the field');\n    }\n\n    public function testMultiRowIndexFile()\n    {\n        $iteration = 3;\n        for ($i = 0; $i < $iteration; ++$i) {\n            $profile = new Profile('token'.$i);\n            $profile->setIp('127.0.0.'.$i);\n            $profile->setUrl('http://foo.bar/'.$i);\n\n            $this->storage->write($profile);\n            $this->storage->write($profile);\n            $this->storage->write($profile);\n        }\n\n        $handle = fopen($this->tmpDir.'/index.csv', 'r');\n        for ($i = 0; $i < $iteration; ++$i) {\n            $row = fgetcsv($handle, null, ',', '\"', '\\\\');\n            $this->assertEquals('token'.$i, $row[0]);\n            $this->assertEquals('127.0.0.'.$i, $row[1]);\n            $this->assertEquals('http://foo.bar/'.$i, $row[3]);\n        }\n        $this->assertFalse(fgetcsv($handle, null, ',', '\"', '\\\\'));\n    }\n\n    #[DataProvider('provideExpiredProfiles')]\n    public function testRemoveExpiredProfiles(string $index, string $expectedOffset)\n    {\n        $file = $this->tmpDir.'/index.csv';\n        file_put_contents($file, $index);\n\n        $r = new \\ReflectionMethod($this->storage, 'removeExpiredProfiles');\n        $r->invoke($this->storage);\n\n        $this->assertSame($expectedOffset, file_get_contents($this->tmpDir.'/index.csv.offset'));\n    }\n\n    public static function provideExpiredProfiles()\n    {\n        $oneHourAgo = new \\DateTimeImmutable('-1 hour');\n\n        yield 'One unexpired profile' => [\n            <<<CSV\n                token0,127.0.0.0,,http://foo.bar/0,{$oneHourAgo->getTimestamp()},,\n\n                CSV,\n            '0',\n        ];\n\n        yield 'One unexpired profile with virtual type' => [\n            <<<CSV\n                token0,127.0.0.0,,http://foo.bar/0,{$oneHourAgo->getTimestamp()},,virtual\n\n                CSV,\n            '0',\n        ];\n\n        $threeDaysAgo = new \\DateTimeImmutable('-3 days');\n\n        yield 'One expired profile' => [\n            <<<CSV\n                token0,127.0.0.0,,http://foo.bar/0,{$threeDaysAgo->getTimestamp()},,\n\n                CSV,\n            '48',\n        ];\n\n        yield 'One expired profile with virtual type' => [\n            <<<CSV\n                token0,127.0.0.0,,http://foo.bar/0,{$threeDaysAgo->getTimestamp()},,virtual\n\n                CSV,\n            '55',\n        ];\n\n        $fourDaysAgo = new \\DateTimeImmutable('-4 days');\n        $threeDaysAgo = new \\DateTimeImmutable('-3 days');\n        $oneHourAgo = new \\DateTimeImmutable('-1 hour');\n\n        yield 'Multiple expired profiles' => [\n            <<<CSV\n                token0,127.0.0.0,,http://foo.bar/0,{$fourDaysAgo->getTimestamp()},,\n                token1,127.0.0.1,,http://foo.bar/1,{$threeDaysAgo->getTimestamp()},,\n                token2,127.0.0.2,,http://foo.bar/2,{$oneHourAgo->getTimestamp()},,\n\n                CSV,\n            '96',\n        ];\n\n        yield 'Multiple expired profiles with virtual type' => [\n            <<<CSV\n                token0,127.0.0.0,,http://foo.bar/0,{$fourDaysAgo->getTimestamp()},,virtual\n                token1,127.0.0.1,,http://foo.bar/1,{$threeDaysAgo->getTimestamp()},,virtual\n                token2,127.0.0.2,,http://foo.bar/2,{$oneHourAgo->getTimestamp()},,virtual\n\n                CSV,\n            '110',\n        ];\n    }\n\n    public function testReadLineFromFile()\n    {\n        $r = new \\ReflectionMethod($this->storage, 'readLineFromFile');\n\n        $h = tmpfile();\n\n        fwrite($h, \"line1\\n\\n\\nline2\\n\");\n        fseek($h, 0, \\SEEK_END);\n\n        $this->assertEquals('line2', $r->invoke($this->storage, $h));\n        $this->assertEquals('line1', $r->invoke($this->storage, $h));\n    }\n\n    protected function cleanDir()\n    {\n        $flags = \\FilesystemIterator::SKIP_DOTS;\n        $iterator = new \\RecursiveDirectoryIterator($this->tmpDir, $flags);\n        $iterator = new \\RecursiveIteratorIterator($iterator, \\RecursiveIteratorIterator::SELF_FIRST);\n\n        foreach ($iterator as $file) {\n            if (is_file($file)) {\n                unlink($file);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/Profiler/ProfilerTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests\\Profiler;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\DataCollectorInterface;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\RequestDataCollector;\nuse Symfony\\Component\\HttpKernel\\Profiler\\FileProfilerStorage;\nuse Symfony\\Component\\HttpKernel\\Profiler\\Profiler;\n\nclass ProfilerTest extends TestCase\n{\n    private string $tmp;\n    private ?FileProfilerStorage $storage = null;\n\n    public function testCollect()\n    {\n        $request = new Request();\n        $request->query->set('foo', 'bar');\n        $request->server->set('REMOTE_ADDR', '127.0.0.1');\n        $response = new Response('', 204);\n        $collector = new RequestDataCollector();\n\n        $profiler = new Profiler($this->storage);\n        $profiler->add($collector);\n        $profile = $profiler->collect($request, $response);\n        $profiler->saveProfile($profile);\n\n        $this->assertSame(204, $profile->getStatusCode());\n        $this->assertSame('GET', $profile->getMethod());\n        $this->assertSame('bar', $profile->getCollector('request')->getRequestQuery()->all()['foo']->getValue());\n    }\n\n    public function testReset()\n    {\n        $collector = $this->getMockBuilder(DataCollectorInterface::class)\n            ->onlyMethods(['collect', 'getName', 'reset'])\n            ->getMock();\n        $collector->method('getName')->willReturn('mock');\n        $collector->expects($this->once())->method('reset');\n\n        $profiler = new Profiler($this->storage);\n        $profiler->add($collector);\n        $profiler->reset();\n    }\n\n    public function testFindWorksWithDates()\n    {\n        $profiler = new Profiler($this->storage);\n\n        $this->assertCount(0, $profiler->find(null, null, null, null, '7th April 2014', '9th April 2014'));\n    }\n\n    public function testFindWorksWithTimestamps()\n    {\n        $profiler = new Profiler($this->storage);\n\n        $this->assertCount(0, $profiler->find(null, null, null, null, '1396828800', '1397001600'));\n    }\n\n    public function testFindWorksWithInvalidDates()\n    {\n        $profiler = new Profiler($this->storage);\n\n        $this->assertCount(0, $profiler->find(null, null, null, null, 'some string', ''));\n    }\n\n    public function testFindWorksWithStatusCode()\n    {\n        $profiler = new Profiler($this->storage);\n\n        $this->assertCount(0, $profiler->find(null, null, null, null, null, null, '204'));\n    }\n\n    public function testIsInitiallyEnabled()\n    {\n        self::assertTrue((new Profiler($this->storage))->isEnabled());\n    }\n\n    public function testDisable()\n    {\n        $profiler = new Profiler($this->storage);\n        $profiler->disable();\n\n        self::assertFalse($profiler->isEnabled());\n    }\n\n    public function testEnable()\n    {\n        $profiler = new Profiler($this->storage);\n        $profiler->disable();\n        $profiler->enable();\n\n        self::assertTrue($profiler->isEnabled());\n    }\n\n    protected function setUp(): void\n    {\n        $this->tmp = tempnam(sys_get_temp_dir(), 'sf_profiler');\n        if (file_exists($this->tmp)) {\n            @unlink($this->tmp);\n        }\n\n        $this->storage = new FileProfilerStorage('file:'.$this->tmp);\n        $this->storage->purge();\n    }\n\n    protected function tearDown(): void\n    {\n        if (null !== $this->storage) {\n            $this->storage->purge();\n            $this->storage = null;\n\n            @unlink($this->tmp);\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/TestHttpKernel.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpKernel\\Tests;\n\nuse Symfony\\Component\\EventDispatcher\\EventDispatcher;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolverInterface;\nuse Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface;\nuse Symfony\\Component\\HttpKernel\\HttpKernel;\n\nclass TestHttpKernel extends HttpKernel implements ControllerResolverInterface, ArgumentResolverInterface\n{\n    public function __construct()\n    {\n        parent::__construct(new EventDispatcher(), $this, null, $this);\n    }\n\n    public function getController(Request $request): callable|false\n    {\n        return $this->callController(...);\n    }\n\n    public function getArguments(Request $request, callable $controller, ?\\ReflectionFunctionAbstract $reflector = null): array\n    {\n        return [$request];\n    }\n\n    public function callController(Request $request)\n    {\n        return new Response('Request: '.$request->getRequestUri());\n    }\n}\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"symfony/http-kernel\",\n    \"type\": \"library\",\n    \"description\": \"Provides a structured process for converting a Request into a Response\",\n    \"keywords\": [],\n    \"homepage\": \"https://symfony.com\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Fabien Potencier\",\n            \"email\": \"fabien@symfony.com\"\n        },\n        {\n            \"name\": \"Symfony Community\",\n            \"homepage\": \"https://symfony.com/contributors\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=8.4\",\n        \"psr/log\": \"^1|^2|^3\",\n        \"symfony/deprecation-contracts\": \"^2.5|^3\",\n        \"symfony/error-handler\": \"^7.4|^8.0\",\n        \"symfony/event-dispatcher\": \"^7.4|^8.0\",\n        \"symfony/http-foundation\": \"^7.4|^8.0\",\n        \"symfony/polyfill-ctype\": \"^1.8\"\n    },\n    \"require-dev\": {\n        \"psr/cache\": \"^1.0|^2.0|^3.0\",\n        \"symfony/browser-kit\": \"^7.4|^8.0\",\n        \"symfony/clock\": \"^7.4|^8.0\",\n        \"symfony/config\": \"^7.4|^8.0\",\n        \"symfony/console\": \"^7.4|^8.0\",\n        \"symfony/css-selector\": \"^7.4|^8.0\",\n        \"symfony/dependency-injection\": \"^7.4|^8.0\",\n        \"symfony/dom-crawler\": \"^7.4|^8.0\",\n        \"symfony/expression-language\": \"^7.4|^8.0\",\n        \"symfony/finder\": \"^7.4|^8.0\",\n        \"symfony/http-client-contracts\": \"^2.5|^3\",\n        \"symfony/process\": \"^7.4|^8.0\",\n        \"symfony/property-access\": \"^7.4|^8.0\",\n        \"symfony/routing\": \"^7.4|^8.0\",\n        \"symfony/serializer\": \"^7.4|^8.0\",\n        \"symfony/stopwatch\": \"^7.4|^8.0\",\n        \"symfony/translation\": \"^7.4|^8.0\",\n        \"symfony/translation-contracts\": \"^2.5|^3\",\n        \"symfony/uid\": \"^7.4|^8.0\",\n        \"symfony/validator\": \"^7.4|^8.0\",\n        \"symfony/var-dumper\": \"^7.4|^8.0\",\n        \"symfony/var-exporter\": \"^7.4|^8.0\",\n        \"twig/twig\": \"^3.21\"\n    },\n    \"provide\": {\n        \"psr/log-implementation\": \"1.0|2.0|3.0\"\n    },\n    \"conflict\": {\n        \"symfony/flex\": \"<2.10\",\n        \"symfony/http-client-contracts\": \"<2.5\",\n        \"symfony/translation-contracts\": \"<2.5\",\n        \"twig/twig\": \"<3.21\"\n    },\n    \"autoload\": {\n        \"psr-4\": { \"Symfony\\\\Component\\\\HttpKernel\\\\\": \"\" },\n        \"exclude-from-classmap\": [\n            \"/Tests/\"\n        ]\n    },\n    \"minimum-stability\": \"dev\"\n}\n"
  },
  {
    "path": "phpunit.xml.dist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:noNamespaceSchemaLocation=\"https://schema.phpunit.de/11.3/phpunit.xsd\"\n         backupGlobals=\"false\"\n         colors=\"true\"\n         bootstrap=\"vendor/autoload.php\"\n         failOnDeprecation=\"true\"\n         failOnRisky=\"true\"\n         failOnWarning=\"true\"\n>\n    <php>\n        <ini name=\"error_reporting\" value=\"-1\" />\n    </php>\n\n    <testsuites>\n        <testsuite name=\"Symfony HttpKernel Component Test Suite\">\n            <directory>./Tests/</directory>\n        </testsuite>\n    </testsuites>\n\n    <source ignoreSuppressionOfDeprecations=\"true\">\n        <include>\n            <directory>./</directory>\n        </include>\n        <exclude>\n            <directory>./Tests</directory>\n            <directory>./vendor</directory>\n        </exclude>\n    </source>\n\n    <extensions>\n        <bootstrap class=\"Symfony\\Bridge\\PhpUnit\\SymfonyExtension\">\n            <parameter name=\"clock-mock-namespaces\" value=\"Symfony\\Component\\HttpFoundation\" />\n        </bootstrap>\n    </extensions>\n</phpunit>\n"
  }
]