Symfony Level Up #4
La newsletter pour performer en Symfony đ
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): ResponseDans 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): ResponseMais 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,
): ResponsePratique, 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 ;-)




