This is the second part of the blog post showcasing the main DX (developer experience) features introduced in Symfony 7.3. Read the first part of this blog post.

Verify URI Signatures

Kevin Bond
Contributed by Kevin Bond in #60102

The feature to sign URIs provides two methods (check() and checkRequest()) to validate the signature of given URLs. In Symfony 7.3, we're adding a new verify() method, similar to check(), but which throws different exceptions if invalid. It doesn't return anything if the signature is valid:

1
2
3
4
5
6
7
8
9
10
11
12
13
try {
    $uriSigner->verify($uri);
} catch (UnSignedUriException $e) {
    // the URI does not contain a signature
    $e->uri; // the URI value
} catch (UnverifiedSignedUriException $e) {
    // the signature is invalid
    $e->uri; // the URI value
} catch (ExpiredSignedUriException $e) {
    // the signature is valid but it's expired
    $e->uri; // the URI value
    $e->expiredAt; // \DateTimeImmutable
}

Using Enums in Config Nodes

Alexandre Daubois
Contributed by Alexandre Daubois in #57686

The Config component allows using PHP enums as possible values for some configuration options. However, you previously needed to provide the possible values explicitly:

1
2
3
4
5
6
7
$rootNode
    ->children()
        ->enumNode('delivery')
            ->values(Delivery::cases())
        ->end()
    ->end()
;

In Symfony 7.3, we're improving this feature so you can pass the FQCN of the enum, and Symfony will get all values automatically:

1
2
3
4
5
6
7
$rootNode
    ->children()
        ->enumNode('delivery')
            ->enumClass(Delivery::class)
        ->end()
    ->end()
;

Improved MapQueryString

Félix Eymonot
Contributed by Félix Eymonot in #59157

The #[MapQueryString] attribute lets you map and validate the request query string into an object like a DTO. In Symfony 7.3, we've added support for a key argument to target a nested part of the query. For example, if the URL is:

1
https://example.org?search[term]=foo&search[category]=bar

Then:

1
2
3
4
5
#[MapQueryString]
// returns an object with $search property = ['term' => 'foo', 'category' => 'bar']

#[MapQueryString(key: 'search')]
// returns an object with $term property = 'foo' and $category property = 'bar'

Native Lazy Objects

Nicolas Grekas
Contributed by Nicolas Grekas in #59913

PHP 8.4 added support for lazy objects, which are only initialized when their state is observed or modified. Symfony already uses lazy-loading extensively to improve performance.

In Symfony 7.3, lazy services will now leverage PHP's native lazy objects when running on PHP 8.4 or higher. No changes are required; just upgrade your PHP version and Symfony will use them automatically.

Defining Array Shapes

Mathias Arlaud
Contributed by Mathias Arlaud in #59827

The TypeInfo component allows extracting and defining type information, e.g. when using it with the JsonStreamer component. In Symfony 7.3, it now supports defining array shapes too:

1
2
3
4
5
6
7
8
9
// resolving type data from a PHPdoc definition
$typeResolver->resolve('array{id: int, name?: string}');
// returns an "ArrayShapeType" instance with 'id' is required, 'name' is optional

// defining an array shape programmatically
$type = Type::arrayShape([
    'id' => Type::int(),
    'name' => ['type' => Type::string(), 'optional' => true],
]);

IPv6 and HTTP/3 Support in HTTP Client

Dmitrii Baranov Mathieu
Contributed by Dmitrii Baranov and Mathieu in #59068 and #59370

In Symfony 7.3, the HttpClient component gains two major improvements.

First, if you're using PHP 8.4 or newer, you can enable HTTP/3 as the version for your requests:

1
2
3
4
5
# config/packages/framework.yaml
framework:
    http_client:
        default_options:
            http_version: '3.0'

Second, the NativeHttpClient now supports IPv6 out of the box. Just upgrade to Symfony 7.3 and you're ready to go.

Logging Channel per Exception

Arkalo2
Contributed by Arkalo2 in #57309

Symfony allows you to log messages to different files using log channels. In Symfony 7.3, this feature is improved so you can configure a different log channel per exception type, helping to separate critical exception logs:

1
2
3
4
5
6
7
8
9
10
# config/packages/framework.yaml
framework:
    exceptions:
        Symfony\Component\HttpKernel\Exception\BadRequestHttpException:
            log_level: debug
            status_code: 422
        Symfony\Component\Security\Core\Exception\AuthenticationException:
            log_channel: security
        Gotenberg\Exceptions\GotenbergApiErroed:
            log_channel: pdf

This is the final blog post in the New in Symfony 7.3 series. We hope you enjoyed it and are excited to upgrade to Symfony 7.3!

Published in #Living on the edge