Level 4 : sortie de Symfony 7.1
Salut collÚgue développeuse / développeur,
QuatriĂšme Ă©dition de cette newsletter, et on dĂ©passe les 160 inscrites et inscrits (bientĂŽt le million) ! Merci Ă nouveau pour ton soutien đ
Si tu veux m'aider Ă faire dĂ©coller 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Ă© et que tu ne veux pas rater les prochaines Ă©ditions, clique sans plus tarder sur le bouton ci-dessous.
Quoi de neuf ?
Ăa y est ! Symfony 7.1 est lĂ đ
Quelques nouveautĂ©s mineures ont Ă©tĂ© dĂ©voilĂ©es depuis ma prĂ©cĂ©dente newsletter oĂč je listais les principales amĂ©liorations. Voici les plus notables :
Un debug simplifié
Il est maintenant possibile dâutiliser dd()
(dump and die) sans lui passer de variables. Utile quand on souhaite seulement stopper le code Ă un endroit sans voir spĂ©cifiquement le contenu dâune variable. Câest lâemoji :bug:
đ qui sâaffichera dans ce cas.
đȘŠ RIP le dd('toto')
De plus jolis <select>
Depuis peu, les navigateurs supportent lâutilisation dâune balise <hr>
au sein dâun <select>
, afin dâavoir des sĂ©parateurs un peu plus jolis. Jusquâalors, Symfony pouvait gĂ©nĂ©rer des sĂ©parateurs, en utilisant simplement des tirets, entre les options et les preferred_choices
. Il est maintenant possible dâutiliser le sĂ©parateur devra ĂȘtre un <hr>
.
Niveau code, il faut ajouter dans les options de ton ChoiceType
, la clé separator
avec <hr>
, et la clé separator_html
Ă true
.
->add('languages', ChoiceType::class, [
'separator' => '<hr>',
'separator_html' => true,
'preferred_choices' => ['php'],
'choices' => $languages,
])
Amélioration du mapping de paramÚtres de route
Il est super pratique dans Symfony, dâindiquer au niveau dâune route, un identifiant comme ceci
#[Route('/{id}', name: 'show')]
public function show(Product $product): Response
Dans ce cas, Symfony et Doctrine sont assez intelligents pour mapper lâid
en paramĂštre de route, avec lâentitĂ© Product
, et aller chercher le bon enregistrement en database (pas besoin dâappeler le ProductRepository
et sa méthode find()
).
Par contre, lorsque plusieurs entitĂ©s sont en jeu dans la mĂȘme route, cela devient plus compliquĂ©, car il nâest plus possible de savoir quel id
correspond Ă quelle entitĂ©, ainsi le code ci-dessous â ne fonctionne pas :
#[Route('/{id}/{id}', name: 'show')]
public function show(Category $category, Product $product): Response
// â ne fonctionne pas
Dans ce simple cas ou le paramĂštre qui sert Ă faire le mapping est lui mĂȘme la clĂ© primaire, une astuce consiste Ă utiliser le nom de lâentitĂ© en paramĂštre. Doctrine ira alors rĂ©cupĂ©rer la propriĂ©tĂ© correspondant Ă la clĂ© primaire de la bonne entitĂ© :
#[Route('/{category}/{product}', name: 'show')]
public function show(Category $category, Product $product): Response
Mais complexifions un peu les choses. Si nous voulons utiliser un slug
du nom du produit dans la route, cela ne fonctionne plus car le paramĂštre {product}
va essayer de mapper par défaut un id
et non un slug
LĂ encore Symfony offre une solution Ă lâaide de lâattribut #[MapEntity]
:
#[Route('/{id}/{slug}', name: 'show')]
public function show(
#[MapEntity(id: 'id')] Category $category,
#[MapEntity(slug: 'slug')] Product $product,
): Response
Pratique, mais tout de mĂȘme un peu verbeux. Câest pourquoi en 7.1, Symfony propose une nouvelle syntaxe supplĂ©mentaire pour faciliter ce type de configuration
#[Route('/{id:category}/{slug:product}', name: 'show')]
Propre ! Cette modification est super pratique et amĂ©liore lâexpĂ©rience de code avec les paramĂštres de route, les rendant plus clairs.
â ïž Mais attention, puisque câest simple Ă implĂ©menter, et empĂȘche les ambiguitĂ©s, il a Ă©tĂ© dĂ©cidĂ© de dĂ©prĂ©cier la syntaxe la plus basique avec uniquement lâid
, qui sera donc certainement retirĂ©e pour la sortie de Symfony 8.0. Câest un changement majeure puisque câĂ©tait la façon de faire par dĂ©faut depuis Symfony 2.0 !
Voici le rĂ©sumĂ© de la sytaxe dĂ©prĂ©ciĂ©e â
(
et donc Ă Ă©viter Ă partir de maintenant), et des syntaxe permises â
â #[Route('/{id}', name: 'show')] // deprecated since 7.1
public function show(Product $product): Response
â
#[Route('/{product}', name: 'show')]
public function show(Product $product): Response
â
#[Route('/{id:product}', name: 'show')]
public function show(Product $product): Response
â
#[Route('/{id}', name: 'show')]
public function show(#[MapEntity(id: 'id')] Product $product): Response
Source : https://symfony.com/blog/new-in-symfony-7-1-mapped-route-parameters
Symfony Jobs
Symfony vient de sortir sont propre Jobboard https://symfony.com/jobs đ€©
Câest une super initiative, car tu es sĂ»r dây trouver uniquement des jobs qui requiert en prioritĂ© du Symfony.
On peut sans doute dĂ©plorer une interface un peu austĂšre et un manque de filtres de recherche, mais câest une toute premiĂšre version et des amĂ©liorations sont prĂ©vues dans le futur, sans doute en fonction de la popularitĂ© de cette page.
On y trouve des offres internationales, quelques unes pour freelance mais la majorité en CDI. Toutes les offres ont obligatoirement une fourchette de salaire.
En plus câest gratuit (pour consulter ou dĂ©poser une offre), un super outil offert Ă la communautĂ© !
Pour rappel, si tu es Freelance que tu cherches des top missions (et que tu nâas pas trouvĂ© ton bonheur sur Symfony Jobs đ) tu peux Ă©galement rejoindre mon programme dâapport dâaffaires en cliquant sur le lien ci-dessous et en remplissant mon formulaire de contact.
Vidéo
Je te parlais dâUX-icon dans une prĂ©cĂ©dente newsletter, je te le (re)prĂ©sente dans une vidĂ©o que jâai sorti il y a quelques jours. Câest vraiment super rapide et pratique Ă utiliser, nâhĂ©site pas Ă tester :-)
Retour dâexpĂ©rience
Ce que jâaime avec le dev, câest quâon a beau avoir des annĂ©es et des annĂ©es dâexpĂ©riences sur un langage ou un framework, il y a toujours un petit truc quâon ne sait pas, alors quâil est peut-ĂȘtre utilisĂ© par la majoritĂ©.
Pour ma part, jâai dĂ©couvert la semaine derniĂšre, lâoption priority
sur les routes (dĂ©cidĂ©mment je parle beaucoup de routes aujourdâhui đ
)
Par dĂ©faut, Symfony recherche un match entre la route de notre requĂȘte en cours, et toutes les routes dĂ©finies. DĂšs quâil trouve un match, il sâarrĂȘte sans aller voir plus loin.
Simple et efficace⊠mais parfois un peu pĂ©nible. Je mâexplique. Il arrive souvent dâavoir des paramĂštres de type string dans une route, un slug par exemple
#[Route('/product/{slug:product}', name: 'show')]
public function show(Product $product): Response
(tu lâauras remarquĂ©, jâen profite pour adopter la nouvelle syntaxe de route dont je parle un peu plus haut dans cette newsletter)
Si jâai une autre route dĂ©finie juste en dessous
#[Route('/product/new', name: 'new')]
public function add(): Response
elle ne sera jamais trouvée. En effet, /product/new
va matcher avec la premiĂšre route, car Symfony va penser que ânewâ est le slug que je recherche (ce qui a de forte chance de provoquer une erreur par ailleurs sâil nâexiste pas).
Pour palier ce problÚme, il faut faire en sorte de placer la définition de route la moins précise en dessous des autres. Une fois fait, /product/new
trouvera un match avant dâatteindre product/{slug:product}
Mais câest pĂ©nible de devoir dĂ©placer des mĂ©thodes entiĂšres dans un fichier. Et quid de dĂ©finitions conflictuelles se trouvant dans des fichiers sĂ©parĂ©s⊠Dans ce cas Symfony commence par regarder les routes en classant les controleurs par ordre alphabĂ©tique⊠un casse tĂȘte.
Eh bien, crois moi ou non (mais bon câest dans la doc donc tu peux me croire), il existe une option priority
pour lâattribut #[Route()]
afin de dĂ©finir lâordre dâinterprĂ©tation de la route (et qui prend donc le dessus sur sa position dans les fichiers). Par dĂ©faut cette prioritĂ© est Ă zĂ©ro pour toutes les routes, et il est possible dâindiquĂ© une valeur positive (pour rendre une route prĂ©cise prioritaire sur les autres) ou nĂ©gative (pour rendre une route moins prioritaire que les autres).
Ce qui nous donne par ex
#[Route('/product/{slug:product}', name: 'show', priority:-1)]
public function add(): Response {...}
#[Route('/product/new', name: 'new')] // default priority:0
public function add(): Response {...}
La route new
a beau ĂȘtre en seconde position, sa prioritĂ© de zĂ©ro est supĂ©rieure Ă celle de show
et matchera donc en premier !
Article utile
Je suis tombé sur cet article il y a quelques jours, qui parle de récursivité dans les tableaux PHP, en utlisant RecursiveIterator
.
Il fait Ă©trangement Ă©cho Ă ma mission en cours, oĂč jâavais exactement ce type de problĂ©matique mĂ©tier. En faisant quelques recherches, jâai bien dĂ©couvert RecursiveIterator
,
envisagĂ© de lâutiliser, mais abondonnĂ© car la doc officielle est vraiment pauvre et les exemples pas trĂšs nombreux. Ca restait obscur et jâai optĂ© pour une autre solution, fonctionnelle mais sans doute moins Ă©lĂ©gante.
Et seulement quelques jours aprĂšs, je dĂ©couvre cet article super bien expliquĂ©, et depuis je dois dire que la refacto me dĂ©mange đ
Bref, je voulais te le partager : https://gbh.fruitbat.io/2024/06/04/php-doing-recursion-with-recursive-iteratoriterators
Conclusion
Jâai commencĂ© cette newsletter par trĂšs inspirĂ©, mais finalement je suis plutĂŽt content, jâai pu abordĂ© pas mal de points diffĂ©rents et lâactualitĂ© fournie de la nouvelle version de Symfony aide bien :-)
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 ;-)