New in Symfony 7.1: Misc Improvements (part 3)
May 31, 2024 • Published by Javier Eguiluz
Symfony 7.1 is backed by:
Expiring Signed URIs
Signed URIs include a hash value that depends on the contents of the URI to ensure their integrity. Symfony provides a service to sign URIs and in Symfony 7.1, we're improving it so you can also make those URIs expire after some time.
Use the new optional second argument of sign()
to define the URI expiration date:
1 2
$url = $this->urlGenerator->generate('document_show', ['id' => $document->getUuid()]);
$signedUrl = $this->uriSigner->sign($url, new \DateTimeImmutable('+10 minutes'));
Expiring URIs include an _expiration
query parameter that you can check on the
server to decide if the URI is still valid.
Improved Linter for Expressions
The ExpressionLanguage component provides a lint()
method to check if the
expression syntax is valid. This method allows to ignore unknown variables but
you can't ignore unknown functions. That's why in Symfony 7.1, we're improving the
linting feature to add more configurability to it:
1 2 3 4 5 6 7
// Before (null means that you decided to ignore unknown variables)
$parser->lint($expr, null);
// After
$parser->lint($expr, [], Parser::IGNORE_UNKNOWN_VARIABLES);
$parser->lint($expr, [], Parser::IGNORE_UNKNOWN_FUNCTIONS);
$parser->lint($expr, [], Parser::IGNORE_UNKNOWN_VARIABLES | Parser::IGNORE_UNKNOWN_FUNCTIONS);
These flags are also available in the parse()
method.
Mapping Boolean Query String Parameters
The #[MapQueryString]
attribute, introduced in Symfony 6.3, takes the data
from the $_GET
PHP superglobal and tries to populate a given typed object with it.
In Symfony 7.1 we're improving the support of boolean query parameters:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// this is the DTO that the app wants to get from the query string data
final readonly class SearchDto
{
public function __construct(public ?bool $restricted = null)
{
}
}
// this is the controller that will map the query string into the DTO
final class MyController
{
#[Route(name: 'search', path: '/search')]
public function __invoke(#[MapQueryString] SearchDto $search): Response
{
// ...
}
}
The URL will be like /search?restricted=...
and this is the logic used to
transform the query string value:
- If the value is
'true'
,1
,yes
oron
, it will be cast to (bool)true
- If the value is
'false'
,0
,no
oroff
, it will be cast to (bool)false
- Otherwise, it will be cast to
null
Create from Timestamp Polyfill
PHP 8.4, to be released on November 21, 2024, will add the createFromTimestamp(int|float $timestamp)
method to the DateTime
and DateTimeImmutable
classes. In Symfony 7.1, we've
added this method as a polyfill in the Clock component so you can start using
them today while keeping your apps future-proof.
Uid Conversion Methods
The Uid component provides utilities to create and work with UUIDs and ULIDs. In Symfony 7.1 we've added some methods to perform more conversions:
1 2 3 4
// UUID/ULID already had a magic __toString() method; now, they also
// have the explicit toString() method
$ulidAsString = (new Ulid())->toString();
$uuidAsString = Uuid::v4()->toString();
The official specification defines eight types of UUIDs. As explained in the Symfony Docs, some of them are no longer recommended (like UUIDv1 and UUIDv6) because there are better alternatives (e.g. UUIDv7).
That's why in Symfony 7.1 we've added some methods to convert between UUID variants so you can migrate to the recommended versions:
1 2 3 4 5
$uuid = Uuid::v1();
$uuidV7 = $uuid->toV7();
$uuid = Uuid::v6();
$uuidV7 = $uuid->toV7();
Throttling HTTP Client
Many third-party APIs limit the number of requests that you can make over a period of time. In Symfony 7.1, we're improving the HttpClient component to implement a throttling client thanks to the RateLimiter component.
First, you must define a rate limiter with the limits imposed by that external API (in this example, we don't want to make more than 10 requests every 5 seconds):
1 2 3 4 5 6 7 8
# config/packages/framework.yaml
framework:
# ...
rate_limiter:
acme_api_limiter:
policy: 'token_bucket'
limit: 10
rate: { interval: '5 seconds', amount: 10 }
Then, associate this rate limiter with your HTTP client using the new
rate_limiter
configuration option:
1 2 3 4 5 6 7 8
# config/packages/framework.yaml
framework:
# ...
http_client:
scoped_clients:
acme_api.client:
base_uri: 'https://...'
rate_limiter: acme_api_limiter
You can now inject this HTTP client anywhere and make requests respecting the limits of the API:
1 2 3 4 5 6 7 8 9
class SomeService
{
public function __construct(
#[Target('acme_api.client')] private HttpClientInterface $httpClient,
) {
}
// ...
}
Help the Symfony project!
As with any Open-Source project, contributing code or documentation is the most common way to help, but we also have a wide range of sponsoring opportunities.
Comments are closed.
To ensure that comments stay relevant, they are closed for old posts.