Level 5 : PHP8.4, upload et emojis
Salut collègue développeuse / développeur,
Cinquième édition de cette newsletter, qui dépasse maintenant les 235 inscrites et inscrits ! Merci à nouveau pour ton soutien 🙏
Si tu veux m'aider à faire décoller encore ce nombre 🚀, n'hésite pas à partager avec tes collègues qui comme toi, souhaitent performer en Symfony.
Et si tu n’es pas encore abonné(e) et que tu ne veux pas rater les prochaines éditions, clique sans plus tarder sur le bouton ci-dessous.
Je suis disponible !
De mon côté, je viens de finir une super mission entamée au début de l’année, où j’ai pu contribuer au développement d’un CMS maison, avec builder graphique de site et rendu via des composants Symfony UX. Si ton entreprise cherche quelqu’un d’expérimenté en ce moment, je suis disponible dès Septembre pour une nouvelle mission, n’hésite pas à me contacter par mail ou directement sur Linkedin.
Quoi de neuf dans l’écosystème ?
Été oblige, les news autour de Symfony se font un peu plus calme. Alors, je ruse un peu et je vais te parler de quelques nouveautés attendues pour PHP8.4, sortie prévue en novembre prochain. Et il va y avoir du lourd !
PHP8.4 : property hook
Peut-être LA plus grosse amélioration : les "Property Hooks", qui vont redessiner la manière d'interagir avec les propriétés en évitant l'ajout systématique de getters et setters qui ne sont pas toujours utiles.
L'idée est de définir ses propriétés comme d'habitude, et si besoin, d'y ajouter via une nouvelle syntaxe, des "hooks" sous la forme des mots-clés get
et set
. Cette nouvelle écriture a pour avantage de réellement relier ce getter et ce setter à la propriété. Auparavant un getName()
n'était finalement relié à la propriété $name
que par simple convention de nommage.
Sans les property hooks (avant PHP 8.4)
class CallMe
{
public string $phone;
public function getPhone(): string
{
return '+33' . $this->phone;
}
public function setPhone(string $phone): void
{
$this->phone = str_replace(['.', '-', '_', ' '], '', $phone);
}
}
$callMe = new ClassMe();
$callMe->setPhone('01-03-03-04-05');
echo $callMe->getPhone(); // +330102030405
Avec l’utilisation des property hook en PHP 8.4
class CallMe
{
public string $phone {
get => '+33' . $this->phone;
set {
$this->phone = str_replace(['.', '-', '_', ' '], '', $value);
}
}
}
$callMe = new ClassMe();
$callMe->phone = '01-03-03-04-05';
echo $callMe->phone; // +330102030405
Plusieurs informations à retenir :
- il existe une syntaxe "one line" de type get => ...
ou une alternative "multi lines" de type get { ... }
- la variable $value
est utilisé par défaut pour le hook set, mais il est possible d'écrire set(string $alernative) { $this->phone = $alternative }
- pour l'utilisation de la propriété, il n'y a plus de getPhone()
ou de setPhone()
. L'affectation d'une valeur appelle automatiquement le hook set
s'il est défini, et l'appel d'une propriété déclenche le hook get
s'il est défini.
Pour en apprendre plus :
https://wiki.php.net/rfc/property-hooks
PHP8.4: new sans parenthèses
Continuons avec la liste des nouveautés de PHP 8.4
Dans cette future version, il sera possible d'instancier une classe et d'appeler directement une méthode, sans avoir recours aux parenthèses autour du new. Un petit plus pas désagréable :-)
class User
{
public function __construct(
private string $firstName,
private string $lastName,
){
}
public function getFullName(): string
{
return $this->firstName . ' ' . $this->lastName;
}
}
// Avant PHP 8.4, parenthèses obligatoires
echo (new User('Bilbo', 'Baggins'))->getFullName();
// PHP 8.4, plus besoin des parenthèses
echo new User('Bilbo', 'Baggins')->getFullName();
PHP8.4: Nouvelles fonctions pour les arrays
De nouvelles fonctions pour les tableaux seront disponibles afin de simplifier la recherche et la validation des données d'un tableau 🎉.:
array_find(array $array, callable $callback): mixed {}
retourne la valeur du premier élément trouvé dans un tableau, qui correspond au callback passé en paramètre. Si rien n’est trouvé, la fonction renvoie null.$firstYearThisCentury = array_find( [1998, 1999, 2000, 2001, 2002], fn($year) => $year > 2000 ); // 2001
array_find_key(array $array, callable $callback): mixed {}
retourne la clé du premier élément trouvé dans un tableau, qui correspond au callback passé en paramètre
$firstUnderMinute = array_find_key( [ 'John' => 68, 'June' => 84, 'Carmen' => 57, 'Bob' => 38, ], fn($time) => $time < 60 ); // Carmen
array_all(array $array, callable $callback): bool {}
retourne true si TOUTES les valeurs du tableau renvoient true en réponse au callback
$onlyAdult = array_all([ 'John' => 22, 'June' => 15, 'Carmen' => 45, ], fn($time) => $age >= 18 ); // false
array_any(array $array, callable $callback): bool {}
retourne true si AUCUNE des valeurs du tableau ne renvoie true en réponse au callback
$onlyAdults = array_any([ 'John' => 17, 'June' => 15, 'Carmen' => 12, ], fn($time) => $age >= 18 ); // true
Plus d'infos sur https://php.watch/versions/8.4/array_find-array_find_key-array_any-array_all
Vidéo
Je te parlais des nouveautés de Symfony 7.1 dans ma précédente newsletter. Parmi celles-ci, il y a le nouvel attribut #[MapUploadedFile]
. J’ai justement réalisé une vidéo pour le présenter plus en détail.
Expérimentation : countryType, drapeaux et emojis 🇫🇷
Le champ de formulaire CountryType de Symfony est très pratique car il permet de récupérer une liste de pays facilement. Cependant (la période des JO y est peut-être pour quelque chose :D) je me suis dit qu’il était dommage de ne pas avoir les drapeaux dans cette liste (sans avoir besoin de passer par une lib JS ou télécharger les images ou icônes de + de 200 drapeaux). Nous allons donc voir comment s’appuyer sur les emojis pour réaliser cela simplement.
C’est un code ISO (2 ou 3 caractères en majuscules qui est renvoyé par le CountryType
. Généralement, il est stocké en base de données, et le nom complet du pays est affiché côté Twig, via le filter |country_name
(attention il faudra installer intl-extra préalablement via composer require twig/intl-extra)
.
{{ 'FR'|country_name }} // France
Cerise sur le gâteau, il est possible de choisir une locale (la locale par défaut de Symfony est utilisée sinon) pour obtenir le nom du pays dans la langue voulue
{{ 'FR'|country_name('de') }} // Frankreich
C’est moins connu, mais il est également possible d’effectuer la même chose côté Symfony via la classe Countries
$countries = Countries::getName('FR'); // France
$countries = Countries::getName('FR', 'de'); // Frankreich
De plus il est possible de récupérer la liste localisée de tous les pays via la méthode getNames(string $locale)
$countries = Countries::getNames('fr');
Lorsque l’on charge un CountryType
, ce champ ne fait guère plus que d’étendre un ChoiceType
, en chargeant une liste de choix basé sur getNames()
.
$builder
->add('country', ChoiceType::class, [
'choices' => array_flip(Countries::getNames()),
])
;
Le array_flip
permet d’échanger clé et valeur afin que le tableau soit de la forme ["France" => "fr"]
et non ["
fr"
=> "
France"
], car c’est la clé qui sera affichée et la value qui sera envoyée dans l’attribut value de la balise <option>
du <select>.
Aujourd’hui tous les drapeaux existent sous forme d’emojis, sous la forme :code_iso_pays:, par ex :fr:
ou :us:
L’idée va donc être de rajouter ce code emoji au nom du pays, puis de demander à Symfony de le traduire du texte vers l’emoji via son composant EmojiTranliterator
.
Ajoutons un array_map
$builder
->add('country', ChoiceType::class, [
'choices' => array_flip(
array_map(function($code, $country) {
return
$country . ' ' . ':' . strtolower($code) . ':';
},
array_keys(Countries::getNames()),
Countries::getNames())
),
])
;
Nous souhaitons obtenir une sortie pour chaque pays qui soit sous la forme ["France :fr:"] => "fr".
array_map
a donc besoin d’une fonction qui prendra en paramètre la clé (le code ISO) et la valeur (le nom du pays), elle va concaténer le code ISO entouré de “:” derrière le nom du pays, puis le array_flip
retournera clés et valeurs du tableau final. Ce résultat est obtenu :
Enfin, nous allons convertir le code emoji du texte vers son image emoji. Pour cela, nous allons utiliser la classe EmojiTransliterator
Il faut instancier la classe dans le construct via la méthode statique create
, en précisant le mode “text-emoji” (texte vers emoji)
class MyCountryFormType extends AbstractType
{
private EmojiTransliterator $transliterator;
public function __construct()
{
$this->transliterator = EmojiTransliterator::create('text-emoji');
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('country', ChoiceType::class, [
// ...
])
;
}
Maintenant que la propriété $transliterator
est disponible, il faut modifier le code de l’array_map
afin de traduire les code emoji texte.
$builder
->add('country', ChoiceType::class, [
'choices' => array_flip(array_map(function($code, $country) {
return
$country . ' ' .
$this->transliterator->transliterate(
':' . strtolower($code) . ':'
);
},
array_keys(Countries::getNames()),
Countries::getNames())),
])
;
Et voilà, les drapeaux s’affichent correctement à côté de chaque nom de pays !
Il est possible de conserver un
CountryType
, mais dans ce cas là il faudra passer également l’option “choice_loader” à null
C’est sans doute plus esthétique et lisible de mettre les drapeaux avant le nom du pays mais la recherche au clavier n’est alors plus disponible (puisque les noms commencent par un emoji), je préfère donc qu’en matière d’accessibilité, les laisser derrière.
Conclusion
Pour rappel, si tu es Freelance que tu cherches des top missions tu peux également rejoindre mon programme d’apport d’affaires en cliquant sur le lien ci-dessous et en remplissant mon formulaire de contact.
Si cette newsletter t'a plu, n’hésite pas à repartager, en parler autour de toi. Et si tu as le moindre commentaire, écris-moi à levelup@sylvainblondeau.dev ou contacte-moi sur mon Linkedin.
À bientôt pour le prochain niveau ;-)