Similar Locale Selection

Florent Morselli
Contributed by Florent Morselli in #52986

Symfony's Request object provides a getPreferredLanguage() method to select the best possible locale for the current user among the list of locales passed to the method:

1
$locale = $request->getPreferredLanguage($supportedLocales) ?? $defaultLocale;

An issue with this method is that is very strict. If $supportedLocales are ['fr_FR', 'en_US'] and $defaultLocale is 'en_US', a user sending the following HTTP header: accept-language: ja-JP,fr_CA;q=0.7,fr;q=0.5 will be assigned en_US as the locale. However, given that the user accepts fr_CA and fr, a better choice would have been fr_FR.

That's why in Symfony 7.1, this method has been improved to try a perfect match first and then try a partial match based only on the language of the locale.

Passing no Arguments to dd() Function

Shamimul Alam
Contributed by Shamimul Alam in #53123

Using a tool like Xdebug is the best way to debug Symfony applications. However, it's also common to use the dump() and dd() functions as a quick and convenient debugging tool. Sometimes you just want the application to stop at some point and use something like dd('here').

It's mandatory to pass at least one argument to dd(), even if you don't want to dump any variables. That's why you pass strings like here in those cases. In Symfony 7.1, you can omit the argument of dd() if you don't want to dump any variables. If you do that, instead of an error you'll see the 🐛 emoji.

Using HTML in ChoiceType Separator

Mathis Boultoureau
Contributed by Mathis Boultoureau in #52447

In the ChoiceType field, we use ------------------- as the visual separator for preferred choices. Browsers recently improved this feature by allowing the <hr> HTML element inside <select>. This shows a much better separator of the select options.

That's why in Symfony 7.1 we're introducing two options so you can customize the separator:

  • separator (defaults to -------------------) it's the content or HTML element used to separate options;
  • separator_html (defaults to false) set it to true when using an HTML element (like <hr>) to render it instead of escaping it.

You can use them like this:

1
2
3
4
5
6
7
8
9
10
11
$builder->add('language', ChoiceType::class, [
    'choices' => [
        'English' => 'en',
        'Spanish' => 'es',
        'Bork' => 'muppets',
        'Pirate' => 'arr',
    ],
    'preferred_choices' => ['muppets', 'arr'],
    'separator' => '<hr>',
    'separator_html' => true,
]);

Add a readFile() Method

Alexander M. Turek
Contributed by Alexander M. Turek in #54173

Symfony's Filesystem component provides platform-independent utilities for filesystem operations and for file/directory paths manipulation. It provides a dumpFile() method to write files but it doesn't provide a method to read files.

You have to use the file_get_contents() function from PHP, which has issues like returning false when there's an error (instead of throwing an exception) and not warning you when you pass a path to a directory instead of a file by mistake.

That's why in Symfony 7.1, we're adding a new readFile() method that either returns the content of a given file or throws an IOException:

1
2
3
4
use Symfony\Component\Filesystem\Filesystem;

$fs = new Filesystem();
$contents = $fs->readFile($someFilePath)

Better Email Delivery Control

Grégoire Pineau
Contributed by Grégoire Pineau in #54044

The Mailer component provides some utilities that come in handy while developing applications. You can use an email catcher, send test emails, disable email delivery entirely or even force all emails to be sent to some address (so you can debug their contents without actually sending them to the real recipients).

In Symfony 7.1, we're improving this last feature so you can exclude some email addresses from it via the allowed_recipients option:

1
2
3
4
5
6
7
8
9
10
11
12
# config/packages/mailer.yaml
when@dev:
    framework:
        mailer:
            envelope:
                # ALL emails will be sent to this address...
                recipients: ['youremail@example.com']
                # ... except those sent to these addresses
                allowed_recipients:
                    - 'internal@example.com'
                    # you can also use regular expressions
                    - 'internal-.*@example.(com|fr)'
Published in #Living on the edge