79319 Commits

Author SHA1 Message Date
Nicolas Grekas
930b073cdd feature #63735 [JsonStreamer] Support date time timezone (mtarld)
This PR was merged into the 8.1 branch.

Discussion
----------

[JsonStreamer] Support date time timezone

| Q             | A
| ------------- | ---
| Branch?       | 8.1
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Issues        | Fix #63099
| License       | MIT

Add timezone support to `DateTimeValueObjectTransformer`, similar to what `DateTimeNormalizer` already does in the Serializer component.

A `TIMEZONE_KEY` option can be passed (as a `\DateTimeZone` or `string`) to convert the timezone when encoding/decoding datetimes.

Commits
-------

7a18ee1e77 [JsonStreamer] Add timezone support to DateTimeValueObjectTransformer
2026-03-23 21:22:27 +01:00
Nicolas Grekas
03b46b8beb minor #63730 [JsonStreamer] Use composer package for RFC 8259 tests (mtarld)
This PR was merged into the 8.1 branch.

Discussion
----------

[JsonStreamer] Use composer package for RFC 8259 tests

| Q             | A
| ------------- | ---
| Branch?       | 8.1
| Bug fix?      | no
| New feature?  | no
| Deprecations? | no
| Issues        | -
| License       | MIT

Replaces the hardcoded test cases in `LexerTest` with the [nst/JSONTestSuite](https://github.com/nst/JSONTestSuite) fetched via Composer, following the same approach as #62761 (JsonPath) and #62642 (Yaml).

Commits
-------

046e795c0b [JsonStreamer] Use composer package for RFC 8259 compliance tests
2026-03-23 21:09:58 +01:00
Nicolas Grekas
255bf0d41d minor #63725 [Console] Fix allowing invalid #[Autowire] references in command arguments (valtzu)
This PR was merged into the 8.1 branch.

Discussion
----------

[Console] Fix allowing invalid `#[Autowire]` references in command arguments

| Q             | A
| ------------- | ---
| Branch?       | 8.1
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Issues        | Related to #63697
| License       | MIT

If a command argument has `#[Autowire]` attribute, it should be validated build-time instead of runtime.

Commits
-------

56f4b1f44c [Console] Fix allowing invalid `#[Autowire]` references in command arguments
2026-03-23 21:05:02 +01:00
Nicolas Grekas
ee4e6730d6 feature #63714 [Console] Add validation constraints support to #[MapInput] (chalasr)
This PR was merged into the 8.1 branch.

Discussion
----------

[Console] Add validation constraints support to `#[MapInput]`

| Q             | A
| ------------- | ---
| Branch?       | 8.1
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Issues        | -
| License       | MIT

This adds automatic validation of `#[MapInput]` DTOs that uses Validator constraints (aligning with `#[MapRequestPayload]` for HTTP controllers).

When Validator is available, constraints on DTO properties are automatically enforced after the input is resolved. When it is not, they are ignored the same as today.

```php
use Symfony\Component\Console\Attribute\Argument;
use Symfony\Component\Console\Attribute\MapInput;
use Symfony\Component\Console\Attribute\Option;
use Symfony\Component\Validator\Constraints as Assert;

class CreateUserInput
{
    #[Argument]
    #[Assert\NotBlank]
    public string $name;

    #[Option]
    #[Assert\Email]
    public ?string $email = null;
}

#[AsCommand('app:create-user')]
class CreateUserCommand
{
    public function __invoke(#[MapInput] CreateUserInput $input): int {
        // validated
    }
}
```

With validation groups:

```php
public function __invoke(
    #[MapInput(validationGroups: ['registration'])] CreateUserInput $input
): int {
```

On failure, a `InputValidationFailedException` (wrapping the original Validator's exception that includes the constraint violations' list) is thrown.

Commits
-------

9ceb0fb59c [Console] Add validation constraints support to `#[MapInput]`
2026-03-23 20:59:39 +01:00
Robin Chalas
9ceb0fb59c [Console] Add validation constraints support to #[MapInput] 2026-03-23 20:58:54 +01:00
Nicolas Grekas
9727380486 bug #63704 [VarExporter] Fix DeepCloner crash with objects using __serialize() (pcescon)
This PR was squashed before being merged into the 8.1 branch.

Discussion
----------

[VarExporter] Fix DeepCloner crash with objects using __serialize()

| Q             | A
| ------------- | ---
| Branch?       | 8.1
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Issues        | Fix #63699
| License       | MIT

## Summary

Fixes a crash when cloning objects that use `__serialize()/__unserialize()` (like `DateTimeImmutable`), particularly affecting PHP 8.5 where `__wakeup()` is deprecated.

## Problem

When cloning objects with `__serialize()/__unserialize()`:
1. The property data format is flat (`['date' => '...']`) rather than scoped (`['Scope' => ['name' => value]]`)
2. In some cases, `__unserialize()` detection via `method_exists()` could fail for internal classes
3. This caused the flat data to reach the property iteration loop, triggering: "foreach() argument must be of type array|object, string given"

## Solution (2 commits)

### Commit 1: Defensive fix in `DeepCloner.php`
- Adds a type check to skip non-array values in the property loop
- Prevents the crash even if flat `__serialize()` data reaches the loop
- Adds tests for `DateTimeImmutable` cloning scenarios

### Commit 2: Root cause fix in `Exporter.php`
- When `__serialize()` is called, ensures `__unserialize()` is properly detected
- Uses both `method_exists()` AND `ReflectionClass::hasMethod()` for robustness
- Properly updates the cache when `__unserialize()` is detected via reflection

## Test plan

- [ ] Run existing VarExporter tests
- [ ] Test with PHP 8.5 to validate DateTimeImmutable handling
- [ ] Verify the reproduction case from #63699 is fixed

Commits
-------

cb978cd1e3 [VarExporter] Fix DeepCloner crash with objects using __serialize()
2026-03-23 20:50:50 +01:00
pcescon
cb978cd1e3 [VarExporter] Fix DeepCloner crash with objects using __serialize() 2026-03-23 20:50:22 +01:00
Mathias Arlaud
7a18ee1e77 [JsonStreamer] Add timezone support to DateTimeValueObjectTransformer 2026-03-23 16:07:33 +01:00
Mathias Arlaud
046e795c0b [JsonStreamer] Use composer package for RFC 8259 compliance tests 2026-03-23 10:23:36 +01:00
valtzu
56f4b1f44c [Console] Fix allowing invalid #[Autowire] references in command arguments 2026-03-22 16:02:26 +02:00
Nicolas Grekas
a7a89a11b4 minor #63713 [Form] fix deprecation notice in ValidatorExtensionTest::testPropertiesInitializedWithEarlyReturn test (santysisi)
This PR was submitted for the 6.4 branch but it was merged into the 8.1 branch instead.

Discussion
----------

[Form] fix deprecation notice in `ValidatorExtensionTest::testPropertiesInitializedWithEarlyReturn` test

| Q             | A
| ------------- | ---
| Branch?       | 8.1
| Bug fix?      | no
| New feature?  | no
| Deprecations? | no
| Issues        | Fix #...
| License       | MIT

Fix deprecation notice triggered in `ValidatorExtensionTest::testPropertiesInitializedWithEarlyReturn`.
The second parameter isn’t necessary for this test, so it can be safely removed.

However, just to be sure, could you confirm this, `@SeverinGloeckle` 🙏?

Deprecation notice screenshot in 8.1

<img width="843" height="400" alt="image" src="https://github.com/user-attachments/assets/e7e2c913-481c-4a94-8c95-0ab7f081ede2" />

Also the [link](https://github.com/symfony/symfony/actions/runs/23364832411/job/67976430562?pr=63712) to that error

Commits
-------

0f89610e87 [Form] fix deprecation notice in `ValidatorExtensionTest::testPropertiesInitializedWithEarlyReturn` test
2026-03-21 14:12:12 +01:00
Santiago San Martin
0f89610e87 [Form] fix deprecation notice in ValidatorExtensionTest::testPropertiesInitializedWithEarlyReturn test 2026-03-21 14:12:08 +01:00
Nicolas Grekas
f7a01d8fa8 feature #63709 [Console] Add optional PSR container parameter to Application (nicolas-grekas)
This PR was merged into the 8.1 branch.

Discussion
----------

[Console] Add optional PSR container parameter to `Application`

| Q             | A
| ------------- | ---
| Branch?       | 8.1
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Issues        |
| License       | MIT

This PR adds an optional `$container` parameter (PSR `ContainerInterface`) to `Console\Application`.

When a container is provided, the application automatically wires:
- `event_dispatcher` → `setDispatcher()`
- `console.argument_resolver` → `setArgumentResolver()`
- `console.command_loader` → `setCommandLoader()`
- `console.command.ids` parameter → eagerly loaded commands (when using Symfony's `ContainerInterface`)
- `services_resetter` → `reset()`
- `kernel.environment` / `kernel.debug` parameters → `getLongVersion()` display

This is the first building block toward enabling pure console applications with dependency injection, without requiring HttpKernel or FrameworkBundle. The wiring logic currently duplicated in `FrameworkBundle\Console\Application` becomes available to any PSR container.

```php
$container = /* any PSR ContainerInterface */;
$app = new Application('my-cli', '1.0', $container);
$app->run();
```

All existing behavior is preserved when no container is passed.

Commits
-------

3753b91ac1 [Console] Add optional PSR container parameter to Application
2026-03-21 14:09:37 +01:00
Nicolas Grekas
3753b91ac1 [Console] Add optional PSR container parameter to Application 2026-03-21 14:01:40 +01:00
Nicolas Grekas
0fed979575 minor #63688 [Process] Widen the type of Process::$commandline (derrabus)
This PR was merged into the 8.1 branch.

Discussion
----------

[Process] Widen the type of `Process::$commandline`

| Q             | A
| ------------- | ---
| Branch?       | 8.1
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Issues        | Follows #62343
| License       | MIT

In #62343, we've narrowed the type of of the `$command` array that needs to be passed to the constructor of `Process` to `list<string>`. However, when processing that array, we pipe it through `array_values()` anyway.

This change created some unnecessary busywork in a codebase I'm working on because that codebase didn't fully ensure that the arrays passed to `Process` is actually a list. I'd like to widen the type to `string[]`.

Commits
-------

c990442da8 [Process] Widen the type of Process::$commandline
2026-03-19 09:24:28 +01:00
Alexander M. Turek
c990442da8 [Process] Widen the type of Process::$commandline 2026-03-18 17:18:42 +01:00
Robin Chalas
ee4f425c6c feature #57598 [Console] Expose the original input arguments and options and to unparse options (theofidry)
This PR was merged into the 8.1 branch.

Discussion
----------

[Console] Expose the original input arguments and options and to unparse options

| Q             | A
| ------------- | ---
| Branch?       | 8.1
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Issues        | None
| License       | MIT

Adds `RawInputInterface` (extending `InputInterface`) with three methods to support forwarding parsed input to child processes:

- `getRawArguments()`: returns arguments without default values merged in
- `getRawOptions()`: returns options without default values merged in
- `unparse(?array $optionNames = null): array`: converts parsed options back to their CLI representation (`['--opt=value', '--flag']`), suitable for passing to `Process`

`Input` (the base class for `ArgvInput`, `ArrayInput`, `StringInput`) implements the new interface. The interface is also wired into the argument resolver, invokable commands, DI, and `SymfonyRuntime` so that commands can type-hint `RawInputInterface` directly.

### Use case

Forwarding the current command's input to a child process, e.g. in [console-parallelization](https://github.com/webmozarts/console-parallelization):

```php
$options = $input->getRawOptions();
unset($options['main-process-only-option']);
$options['child'] = true;

$process = new Process([
    PHP_BINARY, 'bin/console', 'my:command',
    ...$input->getRawArguments(),
    ...$input->unparse(array_keys($options)),
]);
```

### Design notes

- **No BC break**: `InputInterface` is untouched. `RawInputInterface extends InputInterface` so type-hinting it gives access to the full input API.
- **`unparse()` returns `list<string>`** (not a concatenated string) so each element maps to a single process argument — no double-escaping.
- **Default values are excluded** from `getRawArguments()`/`getRawOptions()` so only explicitly passed input is forwarded.

Commits
-------

6475fabac0 [Console] Expose the original input arguments and options and to unparse options
2026-03-18 11:44:49 +07:00
Théo FIDRY
6475fabac0 [Console] Expose the original input arguments and options and to unparse options 2026-03-17 17:55:31 +01:00
Nicolas Grekas
3750e07b66 feature #52134 [HttpKernel] Add option to map empty data with MapQueryString and MapRequestPayload (Jeroeny)
This PR was merged into the 8.1 branch.

Discussion
----------

[HttpKernel] Add option to map empty data with `MapQueryString` and `MapRequestPayload`

| Q             | A
| ------------- | ---
| Branch?       | 8.1
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Issues        | -
| License       | MIT

When `#[MapQueryString]` or `#[MapRequestPayload]` is used on a nullable/default-valued parameter and the query string or request body is empty, the resolver short-circuits and returns `null` without ever calling the serializer. This prevents custom denormalizers from constructing the object.

This PR adds `bool $mapWhenEmpty = false` to both attributes. When `true`, the resolver passes `[]` to `denormalize()` even when no data is present, giving custom denormalizers a chance to populate the DTO.

```php
public function __construct(
    #[MapRequestPayload(mapWhenEmpty: true)] SearchFilters $filters,
) {}
```

**Use case:** a DTO where some fields come from the request and others are injected by a custom denormalizer (e.g. from the security context or session):

```php
class SearchFilters {
    public function __construct(
        public ?string $keyword = null,  // from query string
        public int $userId = 0,          // set by a custom denormalizer
    ) {}
}
```

Without `mapWhenEmpty`, an empty query string yields `null`, the denormalizer never runs. With `mapWhenEmpty: true`, denormalization proceeds and the custom denormalizer can populate `$userId`.

Commits
-------

5117bb6f17 [HttpKernel] Add argument `$mapWhenEmpty` to `MapQueryString` and `MapRequestPayload` for always attempting denormalization with empty query and request payload
2026-03-17 17:21:39 +01:00
Nicolas Grekas
2906620358 feature #41574 [Messenger] Add AmqpPriorityStamp for per-message priority on AMQP transport (Valentin Nazarov)
This PR was merged into the 8.1 branch.

Discussion
----------

[Messenger] Add AmqpPriorityStamp for per-message priority on AMQP transport

| Q             | A
| ------------- | ---
| Branch?       | 8.1
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | Fix #41573
| License       | MIT
| Doc PR        | symfony/symfony-docs#15452

Similarly to #59273 for beanstalkd, this PR adds `AmqpPriorityStamp`, a transport-scoped stamp that sets the AMQP `priority` message attribute when sending through the AMQP transport.

```php
use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpPriorityStamp;

$bus->dispatch($message, [new AmqpPriorityStamp(5)]);
```

The stamp is picked up by `AmqpSender`, which merges the `priority` attribute into the outgoing `AmqpStamp` before publishing.

Per-message priority is inherently transport-specific. Redis, Doctrine/DBAL, and SQS transports have no native priority concept - a generic stamp would silently become a no-op on those. By scoping the stamp to the AMQP bridge (mirroring the existing `BeanstalkdPriorityStamp` introduced in 8.1), the API is honest about what it does and where.

RabbitMQ queues must be declared with the `x-max-priority` argument *before* priority-bearing messages arrive. This is already supported via the transport options:

```yaml
transports:
    async:
        dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
        options:
            queues:
                messages:
                    arguments:
                        x-max-priority: 10
```

`x-max-priority` is already in `Connection::QUEUE_ARGUMENT_ALLOWLIST`, so no additional infrastructure changes are needed.

Pro-Tip: For true priority routing across all transports, configure separate queues and consume them in priority order with `messenger:consume high_priority low_priority`. This PR does not replace that pattern. It complements it for cases where fine-grained per-message priority within a single AMQP queue is needed.

Commits
-------

23991d4abd [Messenger] Add AmqpPriorityStamp for per-message priority on AMQP transport
2026-03-17 17:13:44 +01:00
Valentin Nazarov
23991d4abd [Messenger] Add AmqpPriorityStamp for per-message priority on AMQP transport 2026-03-17 17:13:13 +01:00
Nicolas Grekas
6903a715af Merge branch '8.0' into 8.1
* 8.0:
  Fix merge
  [VarDumper] Wrong dumper output for Accept: aplication/json requests
  [HttpKernel] Reset router locale to default when finishing main request
  Only decrement pendingRequests when it's more than zero
  [Dotenv] Fix self-referencing variables with defaults and env key resolution during deferred expansion
  Improve Bulgarian translations in validators.bg.xlf
  [Cache] Fix ChainAdapter ignoring item expiry when propagating to earlier adapters
  [Form] Fix typed property initialization in ValidatorExtension
  [Messenger] Fix duplicate pending messages in Redis transport with batch handlers
  Fix deprecation notices for "@method" annotations when implementing interfaces directly
2026-03-17 16:35:01 +01:00
Nicolas Grekas
9c24cc1dbe Merge branch '7.4' into 8.0
* 7.4:
  Fix merge
2026-03-17 16:33:01 +01:00
Nicolas Grekas
e197e851bd Fix merge 2026-03-17 16:32:54 +01:00
Nicolas Grekas
abc913b863 Merge branch '7.4' into 8.0
* 7.4:
  [VarDumper] Wrong dumper output for Accept: aplication/json requests
  [HttpKernel] Reset router locale to default when finishing main request
  Only decrement pendingRequests when it's more than zero
  [Dotenv] Fix self-referencing variables with defaults and env key resolution during deferred expansion
  Improve Bulgarian translations in validators.bg.xlf
  [Cache] Fix ChainAdapter ignoring item expiry when propagating to earlier adapters
  [Form] Fix typed property initialization in ValidatorExtension
  [Messenger] Fix duplicate pending messages in Redis transport with batch handlers
  Fix deprecation notices for "@method" annotations when implementing interfaces directly
2026-03-17 15:00:10 +01:00
Nicolas Grekas
a8f4940a65 bug #63648 [VarDumper] Wrong dumper output for Accept: aplication/json requests (rfcdt)
This PR was merged into the 7.4 branch.

Discussion
----------

[VarDumper] Wrong dumper output for Accept: aplication/json requests

| Q             | A
| ------------- | ---
| Branch?       | 7.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Issues        | Fix #63601
| License       | MIT

`CliDumper::$defaultOutput` is `php://stdout`, which in PHP-FPM is redirected to the error log — not the HTTP response body. Only `php://output` goes through PHP's output buffering into the actual response.

The dumper selection fell back to `CliDumper` for any Accept header that wasn't `html` or `*/*`, so `dump()`/`dd()` output silently disappeared for JSON API requests under PHP-FPM. The same issue also affected the `server`/`tcp` format fallback dumper.

This PR fixes the issue by using `new CliDumper('php://output')` in web SAPI contexts where the Accept header is not HTML/`*/*`, and refactors the `switch(true)` into `match($format)` + an extracted `selectDumperForAccept()` method.

Commits
-------

f663a6ab95 [VarDumper] Wrong dumper output for Accept: aplication/json requests
2026-03-17 14:59:26 +01:00
rfcdt
f663a6ab95 [VarDumper] Wrong dumper output for Accept: aplication/json requests 2026-03-17 14:59:19 +01:00
Nicolas Grekas
c9ef7318ef Merge branch '6.4' into 7.4
* 6.4:
  [HttpKernel] Reset router locale to default when finishing main request
  Only decrement pendingRequests when it's more than zero
  [Dotenv] Fix self-referencing variables with defaults and env key resolution during deferred expansion
  Improve Bulgarian translations in validators.bg.xlf
  [Cache] Fix ChainAdapter ignoring item expiry when propagating to earlier adapters
  [Form] Fix typed property initialization in ValidatorExtension
  [Messenger] Fix duplicate pending messages in Redis transport with batch handlers
  Fix deprecation notices for "@method" annotations when implementing interfaces directly
2026-03-17 14:25:29 +01:00
Nicolas Grekas
860203996b bug #63674 [Dotenv] Fix self-referencing variables with defaults and env key resolution during deferred expansion (nicolas-grekas)
This PR was merged into the 6.4 branch.

Discussion
----------

[Dotenv] Fix self-referencing variables with defaults and env key resolution during deferred expansion

| Q             | A
| ------------- | ---
| Branch?       | 6.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Issues        | Fix #63664, Fix #63668
| License       | MIT

The deferred variable expansion introduced in #63496 broke two things:

1. Self-referencing variables with defaults no longer resolve

A common pattern for providing defaults that can be overridden by host environment variables:

```
MY_VAR="${MY_VAR:-default_value}"
DB_HOST="${DB_HOST:-localhost}"
```

After deferred expansion, `populate()` writes the raw string `${MY_VAR:-default_value}` into `$_ENV['MY_VAR']` before resolution. When `resolveLoadedVars()` later tries to resolve it, the lookup finds that non-empty raw string in `$_ENV` and never triggers the default.

2. Env key with variable references breaks `loadEnv()` file selection

`loadEnv()` reads `APP_ENV` between `doLoad()` and `resolveLoadedVars()` to determine which additional `.env.*` files to load. With deferred expansion, the raw unresolved value (e.g. `${APP_ENV:-dev}`) is used for file selection, so `.env.dev` is never loaded.

Commits
-------

92270233e0 [Dotenv] Fix self-referencing variables with defaults and env key resolution during deferred expansion
2026-03-17 14:12:41 +01:00
Nicolas Grekas
b3dfc62f9d bug #63676 [HttpKernel] Reset router locale to default when finishing main request (guillaumeVDP)
This PR was squashed before being merged into the 6.4 branch.

Discussion
----------

[HttpKernel] Reset router locale to default when finishing main request

| Q             | A
| ------------- | ---
| Branch?       | 6.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Issues        | Fix #61762
| License       | MIT

Commits
-------

d70f4c2bd5 [HttpKernel] Reset router locale to default when finishing main request
2026-03-17 12:33:04 +01:00
Guillaume VDP
d70f4c2bd5 [HttpKernel] Reset router locale to default when finishing main request 2026-03-17 12:32:31 +01:00
Nicolas Grekas
2701045176 bug #63679 [WebProfilerBundle] Only decrement pendingRequests when it's more than zero (andyexeter)
This PR was merged into the 6.4 branch.

Discussion
----------

[WebProfilerBundle] Only decrement pendingRequests when it's more than zero

| Q             | A
| ------------- | ---
| Branch?       |  6.4
| Bug fix?      | yes
| New feature?  | no <!-- if yes, also update src/**/CHANGELOG.md -->
| Deprecations? | no <!-- if yes, also update UPGRADE-*.md and src/**/CHANGELOG.md -->
| Issues        | Fix #63667 <!-- prefix each issue number with "Fix #"; no need to create an issue if none exists, explain below -->
| License       | MIT

This PR fixes the linked issue by ensuring the `pendingRequests` variable never goes below zero.

Commits
-------

1dfe48b014 Only decrement pendingRequests when it's more than zero
2026-03-17 11:35:59 +01:00
andyexeter
1dfe48b014 Only decrement pendingRequests when it's more than zero 2026-03-17 09:05:06 +00:00
Nicolas Grekas
92270233e0 [Dotenv] Fix self-referencing variables with defaults and env key resolution during deferred expansion 2026-03-16 15:58:12 +01:00
Nicolas Grekas
cfe04b4673 feature #63661 [Runtime] Add FrankenPhpWorkerResponseRunner for simple response return (guillaume-sainthillier)
This PR was merged into the 8.1 branch.

Discussion
----------

[Runtime] Add FrankenPhpWorkerResponseRunner for simple response return

| Q             | A
| ------------- | ---
| Branch?       | 8.1
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Issues        | -
| License       | MIT

This introduces `FrankenPhpWorkerResponseRunner`, a companion to the existing `FrankenPhpWorkerRunner`. While `FrankenPhpWorkerRunner` handles the full kernel lifecycle (request creation, handling,
  termination), this new runner is designed for cases where the application already provides a `Response` object — it simply sends it within the FrankenPHP worker loop.

Usage :

```php
  // public/index.php
  use App\Kernel;

  require_once dirname(__DIR__).'/vendor/autoload_runtime.php';

  return function (array $context) {
      if($context['APP_MAINTENANCE']) {
          return new Response('....', 503);
      }

      $request = \Symfony\Component\HttpFoundation\Request::createFromGlobals();

      return $kernel->handle($request);
  };

Commits
-------

9b80296b32 Add FrankenPhpWorkerResponseRunner for simple response return in symfony/runtime
2026-03-16 15:09:33 +01:00
Nicolas Grekas
8a9eaa54f7 minor #63659 Improve Bulgarian translations in validators.bg.xlf (danielbg14)
This PR was squashed before being merged into the 6.4 branch.

Discussion
----------

 Improve Bulgarian translations in validators.bg.xlf

| Q             | A
| ------------- | ---
| Branch?       | 6.4
| Bug fix?      | yes
| New feature?  | no <!-- if yes, also update src/**/CHANGELOG.md -->
| Deprecations? | no <!-- if yes, also update UPGRADE-*.md and src/**/CHANGELOG.md -->
| Issues        | Fix #59411  <!-- prefix each issue number with "Fix #"; no need to create an issue if none exists, explain below -->
| License       | MIT

## Description

Improved several Bulgarian translations in `validators.bg.xlf`.

Changes include:
- Simplified wording (e.g. "Тази стойност" → "Стойността")
- Improved wording for pixel validation messages
- Fixed spacing issue with `px`
- Made translations more consistent with the existing Bulgarian style

Commits
-------

0e245874fd  Improve Bulgarian translations in validators.bg.xlf
2026-03-16 14:50:04 +01:00
Daniel Konstantinov
0e245874fd Improve Bulgarian translations in validators.bg.xlf 2026-03-16 14:49:57 +01:00
Nicolas Grekas
114ca762ea bug #63655 [Cache] Fix ChainAdapter ignoring item expiry when propagating to earlier adapters (guillaumeVDP)
This PR was merged into the 6.4 branch.

Discussion
----------

[Cache] Fix ChainAdapter ignoring item expiry when propagating to earlier adapters

| Q             | A
| ------------- | ---
| Branch?       | 6.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Issues        | Fix #59947
| License       | MIT

When `ChainAdapter::getItem()` found a cache miss in adapter N and a hit in adapter N+1, it copied the item back into the earlier adapter via `syncItem()`. However, `syncItem` relied on `metadata['expiry']` to restore the original TTL and that metadata was never stored for items that had an explicit TTL but no tags.

The result: every such item was re-stored with the chain's `defaultLifetime` instead of its original expiry. An item set with `expiresAfter(2)` could end up living 100 seconds in the primary cache.

Commits
-------

61e994fa4f [Cache] Fix ChainAdapter ignoring item expiry when propagating to earlier adapters
2026-03-16 14:43:41 +01:00
Guillaume VDP
61e994fa4f [Cache] Fix ChainAdapter ignoring item expiry when propagating to earlier adapters 2026-03-16 14:41:56 +01:00
Guillaume Sainthillier
9b80296b32 Add FrankenPhpWorkerResponseRunner for simple response return in symfony/runtime 2026-03-16 12:40:40 +01:00
Nicolas Grekas
88c396f4bd bug #63656 [Form] Fix typed property initialization in ValidatorExtension (SeverinGloeckle)
This PR was merged into the 6.4 branch.

Discussion
----------

[Form] Fix typed property initialization in ValidatorExtension

| Q             | A
| ------------- | ---
| Branch?       | 6.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? |no
| License       | MIT

The early return in the ValidatorExtension constructor added in 37b2f68f4c prevents typed properties from being initialized when a Form constraint already existed, causing PHP errors when the extension is used:

```
Typed property Symfony\Component\Form\Extension\Validator\ValidatorExtension::$validator
must not be accessed before initialization
```

## Changes Made

* Code Fix: Moved property initialization before the early return check in the constructor.
* Test Addition: Added `testPropertiesInitializedWithEarlyReturn()` to verify the fix.

## Solution

This fix ensures:
* All properties are initialized before any early return.
* The original duplicate constraint prevention still works.
* The extension remains fully functional in all use cases.

## Testing
Added test case that triggers the early return condition and verifies that the extension remains functional to prevent future regressions.

Commits
-------

77676c8cc9 [Form] Fix typed property initialization in ValidatorExtension
2026-03-16 11:46:48 +01:00
Nicolas Grekas
0ea1ee0505 bug #63643 [Messenger] Fix duplicate pending messages in Redis transport with batch handlers (wazum)
This PR was merged into the 6.4 branch.

Discussion
----------

[Messenger] Fix duplicate pending messages in Redis transport with batch handlers

| Q             | A
| ------------- | ---
| Branch?       | 6.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Issues        | Fix #44400, Fix #49023
| License       | MIT

The Redis transport is currently broken when used with `BatchHandlerInterface`. The root cause is in how `Connection::get()` reads pending messages.

When a batch handler calls `get()` repeatedly to accumulate messages before flushing, the transport always passes ID `0` to `XREADGROUP`, which makes Redis return pending entries from the very beginning. Since previously fetched messages haven't been acked yet (that's the whole point of batching), the first pending message is returned over and over. This fills the batch with duplicates of the same message, and when the handler tries to ack them, all but the first fail with `Could not acknowledge redis message`.

The issue has been open since 2021 and people have been working around it with custom transport decorators, message deduplication via UUIDs, and other workarounds — none of which should be necessary.

### The fix

Replace the boolean `$couldHavePendingMessages` flag with two things:

- A **cursor** (`$lastPendingMessageId`) that advances past each returned message, so successive `XREADGROUP` calls iterate through the pending list instead of restarting from the beginning every time.
- An **in-flight registry** (`$inflightIds`) that tracks which message IDs have already been delivered to the worker. When a claim resets the cursor back to `0`, any previously delivered messages are skipped. IDs are removed from the registry when `ack()` or `reject()` is called.

This also fixes #49023: the old code unconditionally advanced `$nextClaim` at the end of `claimOldPendingMessages()`, even after a successful claim. That meant the worker had to wait the full `claim_interval` (default 60s) before it could claim the next abandoned message. Now the timer only advances when there is genuinely nothing left to claim, so multiple abandoned messages can be recovered in sequence.

The `get()` method has been refactored from a single method with recursive self-calls into smaller focused methods (`getPendingMessage()`, `getNewMessage()`, `handleDelayedMessages()`, `xReadGroup()`), which makes the control flow easier to follow and test.

Commits
-------

9f5574568a [Messenger] Fix duplicate pending messages in Redis transport with batch handlers
2026-03-16 11:44:53 +01:00
Nicolas Grekas
510fb07f79 feature #63666 [Messenger] Allow configuring the service reset interval in the messenger:consume command via the --no-reset option (nicolas-grekas)
This PR was merged into the 8.1 branch.

Discussion
----------

[Messenger] Allow configuring the service reset interval in the `messenger:consume` command via the `--no-reset` option

| Q             | A
| ------------- | ---
| Branch?       | 8.1
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Issues        | -
| License       | MIT

This PR extends the `--no-reset` option of the `messenger:consume` command to optionally accept a numeric interval, allowing services to be reset every N messages instead of the current all-or-nothing behavior.

`--no-reset` now accepts an optional integer value:
- `--no-reset` (no value) — disables service resetting entirely (same as before)
- `--no-reset=100` — resets services every 100 messages
- Without the flag — resets after every message (default, unchanged)

This is useful when resetting after every message is expensive, but never resetting leads to memory leaks or stale state.

Commits
-------

def4af2d00 [Messenger] Allow configuring the service reset interval in the `messenger:consume` command via the `--no-reset` option
2026-03-16 09:54:28 +01:00
Nicolas Grekas
def4af2d00 [Messenger] Allow configuring the service reset interval in the messenger:consume command via the --no-reset option 2026-03-16 09:53:28 +01:00
Nicolas Grekas
23a28cf808 feature #63665 [Messenger] Add MessageExecutionStrategyInterface and refactor Worker to use it (nicolas-grekas)
This PR was merged into the 8.1 branch.

Discussion
----------

[Messenger] Add `MessageExecutionStrategyInterface` and refactor `Worker` to use it

| Q             | A
| ------------- | ---
| Branch?       | 8.1
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Issues        | -
| License       | MIT

This PR extracts the message dispatching logic from `Worker` into a `MessageExecutionStrategyInterface`, making the execution model pluggable.

Today, `Worker` handles messages synchronously inline. This refactoring introduces:
- **`MessageExecutionStrategyInterface`** — defines `execute()`, `wait()`, `flush()`, `shouldPauseConsumption()`, and `shutdown()`, giving full control over how and when messages are dispatched and acknowledged.
- **`SyncMessageExecutionStrategy`** — the default implementation, preserving the current synchronous behavior.
- **`DeferredBatchMessageQueue`** — replaces the raw `\SplObjectStorage` used for batch handler tracking with a dedicated class that supports time-based flushing.

`Worker` now delegates to the strategy for dispatch and accepts an optional `?MessageExecutionStrategyInterface` constructor argument (defaults to `SyncMessageExecutionStrategy`). Existing behavior is unchanged.

This is a preparatory step for adding parallel message processing via a `--concurrency` option, see https://github.com/symfony/symfony/pull/63650.

Commits
-------

ce5ffb39bb [Messenger] Add `MessageExecutionStrategyInterface` and refactor `Worker` to use it
2026-03-16 09:28:53 +01:00
Nicolas Grekas
ce5ffb39bb [Messenger] Add MessageExecutionStrategyInterface and refactor Worker to use it 2026-03-16 09:25:23 +01:00
Nicolas Grekas
754e299ec9 feature #63662 [Messenger] Add a --fetch-size option to the messenger:consume command to control how many messages are fetched per iteration (nicolas-grekas)
This PR was merged into the 8.1 branch.

Discussion
----------

[Messenger] Add a `--fetch-size` option to the `messenger:consume` command to control how many messages are fetched per iteration

| Q             | A
| ------------- | ---
| Branch?       | 8.1
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Issues        | -
| License       | MIT

Related to #63650.

Currently, receivers always fetch one message at a time, which means one round-trip to the transport per message. This PR allows fetching multiple messages at once, so the transport can fulfill that in a single round-trip when supported (e.g. SQS supports up to 10 messages per `ReceiveMessage` call, Redis supports `XREADGROUP COUNT`, AMQP supports `basic_get` in a loop with a known limit, Doctrine supports `LIMIT`).

A new `--fetch-size` option is added to the `messenger:consume` command:

```
php bin/console messenger:consume async --fetch-size=8
```

Under the hood, this adds a `$fetchSize` argument to `ReceiverInterface::get()` and `QueueReceiverInterface::getFromQueues()`:

```php
// ReceiverInterface
public function get(/* int $fetchSize = 1 */): iterable;

// QueueReceiverInterface
public function getFromQueues(array $queueNames /* , int $fetchSize = 1 */): iterable;
```

The argument is added as a commented-out parameter to preserve backward compatibility with existing custom receivers.

All built-in transports (AMQP, Doctrine, Redis, SQS, Beanstalkd, InMemory, Sync, Scheduler) are updated to support the new argument.

Commits
-------

e4536ac7ef [Messenger] Add a `--fetch-size` option to the `messenger:consume` command to control how many messages are fetched per iteration
2026-03-16 08:46:08 +01:00
Nicolas Grekas
e4536ac7ef [Messenger] Add a --fetch-size option to the messenger:consume command to control how many messages are fetched per iteration 2026-03-16 08:45:09 +01:00
Nicolas Grekas
3f0ca55a3d feature #63663 [Contracts] Add ContainerAwareInterface (nicolas-grekas)
This PR was merged into the 8.1 branch.

Discussion
----------

[Contracts] Add `ContainerAwareInterface`

| Q             | A
| ------------- | ---
| Branch?       | 8.1
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Issues        | -
| License       | MIT

Related to https://github.com/symfony/symfony/pull/63650.

This PR adds a `ContainerAwareInterface` to `symfony/service-contracts`, providing a standard way for objects to expose their service container.

The immediate use case is the Messenger component: parallel workers need to bootstrap the application and access the container to resolve the message bus. Without a contract, there's no reliable way to get the container from the console `Application` object in a decoupled manner.

The interface is intentionally minimal — a single `getContainer(): ContainerInterface` method — and `FrameworkBundle\Console\Application` implements it, booting the kernel if needed.

Commits
-------

8c158e0520 [Contracts] Add `ContainerAwareInterface`
2026-03-16 08:28:02 +01:00
Nicolas Grekas
8c158e0520 [Contracts] Add ContainerAwareInterface 2026-03-15 19:28:19 +01:00