Série : Symfony 7
Fichiers : https://github.com/NouvelleTechno/OpenBlog
Dans ce tutoriel, nous allons nous concentrer sur la mise en place de validations de formulaire côté frontend pour notre projet Symfony, plus spécifiquement pour le formulaire d'inscription de notre application OpenBlog. Cette approche complète les validations backend que nous avons mises en place dans le tutoriel précédent.
Pourquoi la Validation Frontend ?
La validation frontend est essentielle pour améliorer l'expérience utilisateur en fournissant des retours immédiats sur les erreurs de saisie, sans avoir besoin de soumettre le formulaire. Cependant, il est crucial de se rappeler que cette validation peut être contournée, d'où l'importance de la validation backend.
Mise en Place des Validations sur le Formulaire d'Inscription
Nous allons commencer par ajouter un indicateur de complexité pour le mot de passe, ainsi que des vérifications pour le pseudo et l'email.
Ajout de l'Indicateur de Complexité du Mot de Passe
Tout d'abord, nous allons modifier le template register.html.twig
pour ajouter un indicateur de complexité du mot de passe. Voici comment faire :
<div>
<label for="password">Mot de passe</label>
{{ form_widget(form.plainPassword) }}
<p>Complexité du mot de passe : <span id="entropie" class="text-red">Très faible</span></p>
</div>
Ensuite, nous allons styliser les niveaux de complexité avec du CSS :
.text-red { color: red; }
.text-orange { color: orange; }
.text-green { color: green; }
Ces styles seront utilisés pour indiquer visuellement la complexité du mot de passe.
Création du Script JavaScript pour la Validation
Nous allons maintenant créer un fichier JavaScript pour gérer la validation en temps réel du formulaire.
Créez un fichier register.js
dans le dossier assets/js/
et ajoutez le code suivant :
// Variables booléennes
let pseudo = false;
let email = false;
let rgpd = false;
let pass = false;
// On charge les éléments du formulaire
document.querySelector("#registration_form_nickname").addEventListener("input", checkPseudo);
document.querySelector("#registration_form_email").addEventListener("input", checkEmail);
document.querySelector("#registration_form_agreeTerms").addEventListener("input", checkRgpd);
document.querySelector("#registration_form_plainPassword").addEventListener("input", checkPass);
function checkPseudo(){
pseudo = this.value.length > 2;
checkAll();
}
function checkEmail(){
let regex = new RegExp("\\S+@\\S+\\.\\S+");
email = regex.test(this.value);
checkAll();
}
function checkRgpd(){
rgpd = this.checked;
checkAll();
}
function checkAll(){
document.querySelector("#submit-button").setAttribute("disabled", "disabled");
if(email && pseudo && pass && rgpd){
document.querySelector("#submit-button").removeAttribute("disabled");
}
}
const PasswordStrength = {
STRENGTH_VERY_WEAK: 'Très faible',
STRENGTH_WEAK: 'Faible',
STRENGTH_MEDIUM: 'Moyen',
STRENGTH_STRONG: 'Fort',
STRENGTH_VERY_STRONG: 'Très fort',
}
function checkPass(){
// On récupère le mot de passe tapé
let mdp = this.value;
// On récupère l'élément d'affichage de l'entropie
let entropyElement = document.querySelector("#entropy");
// On évalue la force du mot de passe
let entropy = evaluatePasswordStrength(mdp);
entropyElement.classList.remove("text-red", "text-orange", "text-green");
// On attribue la couleur en fonction de l'entropie
switch(entropy){
case 'Très faible':
entropyElement.classList.add("text-red");
pass = false;
break;
case 'Faible':
entropyElement.classList.add("text-red");
pass = false;
break;
case 'Moyen':
entropyElement.classList.add("text-orange");
pass = false;
break;
case 'Fort':
entropyElement.classList.add("text-green");
pass = true;
break;
case 'Très fort':
entropyElement.classList.add("text-green");
pass = true;
break;
default:
entropyElement.classList.add("text-red");
pass = false;
}
entropyElement.textContent = entropy;
checkAll();
}
function evaluatePasswordStrength(password){
// On calcule la longueur du mot de passe
let length = password.length;
// Si le mot de passe est vide
if(!length){
return PasswordStrength.STRENGTH_VERY_WEAK;
}
// On crée un objet qui contiendra les caractères et leur nombre
let passwordChars = {};
for(let index = 0; index < password.length; index++){
let charCode = password.charCodeAt(index);
passwordChars[charCode] = (passwordChars[charCode] || 0) + 1;
}
// Compte le nombre de caractères différents dans le mot de passe
let chars = Object.keys(passwordChars).length;
// On initialise les variables des types de caractères
let control = 0, digit = 0, upper = 0, lower = 0, symbol = 0, other = 0;
for(let [chr, count] of Object.entries(passwordChars)){
chr = Number(chr);
if(chr < 32 || chr === 127){
// Caractère de contrôle
control = 33;
}else if(chr >= 48 && chr <= 57){
// Chiffres
digit = 10;
}else if(chr >= 65 && chr <= 90){
// Majuscules
upper = 26;
}else if(chr >= 97 && chr <= 122){
// Minuscules
lower = 26;
}else if(chr >= 128){
// Autres caractères
other = 128;
}else{
// Symboles
symbol = 33;
}
}
// On calcule le pool de caractères
let pool = control + digit + upper + lower + other + symbol;
// Formule de calcul de l'entropie
let entropy = chars * Math.log2(pool) + (length - chars) * Math.log2(chars);
if(entropy >= 120){
return PasswordStrength.STRENGTH_VERY_STRONG;
}else if(entropy >= 100){
return PasswordStrength.STRENGTH_STRONG;
}else if(entropy >= 80){
return PasswordStrength.STRENGTH_MEDIUM;
}else if(entropy >= 60){
return PasswordStrength.STRENGTH_WEAK;
}else{
return PasswordStrength.STRENGTH_VERY_WEAK;
}
}
Ce script ajoute des écouteurs d'événements sur les champs du formulaire pour valider les entrées en temps réel. Il calcule la complexité du mot de passe et met à jour l'interface en conséquence.
Intégration du JavaScript dans Symfony
Enfin, nous devons inclure ce script dans notre page de formulaire. Pour cela, modifiez importmap.php
pour ajouter notre script register.js
:
'register' => [
'path' => './assets/js/register.js',
'entrypoint' => true,
],
Puis, dans votre template register.html.twig
, ajoutez le bloc importmap
pour charger ce script :
{% block importmap %}
{{ parent() }}
{{ importmap('register') }}
{% endblock %}
Conclusion
En combinant les validations frontend et backend, nous assurons que notre formulaire est à la fois sécurisé et convivial. La validation frontend fournit des retours immédiats à l'utilisateur, tandis que la validation backend garantit l'intégrité des données.
Obtenir de l'aide
Pour obtenir de l'aide, vous pouvez accéder au serveur Discord pour une entraide par chat.