Development

Documentation/fr_FR/askeet/trunk/D6 (diff)

You must first sign up to be able to contribute.

Changes between Version 2 and Version 3 of Documentation/fr_FR/askeet/trunk/D6

Show
Ignore:
Author:
mikael.randy (IP: 88.160.26.16)
Timestamp:
02/14/08 00:02:32 (10 years ago)
Comment:

Poursuite de la traduction

Legend:

Unmodified
Added
Removed
Modified
  • Documentation/fr_FR/askeet/trunk/D6

    v2 v3  
    1616Précédemment dans Symfony 
    1717------------------------- 
    18 Au cours du [cinquième jour] (4.txt), vous avez dû manipuler les templates et les actions. Les formulaires et les pagineur n'ont plus aucun secret pour vous. Mais après avoir construit le formulaire de connexion, vous attendez surement de nous que nous vous montrions comment restreindre l'accès à certaines fonctionnalités pour les membres non-authorisés. C'est ce que nous allons réaliser aujourd'hui, a l'aide de plusieurs validation de formulaires. Comme nous allons également ajouter des classes personnelles à l'application, vous devriez également comprendre les concepts exposés dans le  chapitre concernant les [extensions personnelles] (http://www.symfony-project.com/book/1_0/07-Inside-the-View-Layer) dans le livre Symfony. 
     18Au cours du [cinquième jour] (4.txt), vous avez dû manipuler les templates et les actions. Les formulaires et les pagineurs n'ont plus aucun secret pour vous. Mais après avoir construit le formulaire de connexion, vous attendez sûrement de nous que nous vous montrions comment restreindre l'accès à certaines fonctionnalités pour les membres non-autorisés. C'est ce que nous allons réaliser aujourd'hui, a l'aide de plusieurs validation de formulaires. Comme nous allons également ajouter des classes personnelles à l'application, vous devriez également comprendre les concepts exposés dans le  chapitre concernant les [extensions personnelles] (http://www.symfony-project.com/book/1_0/07-Inside-the-View-Layer) dans le livre Symfony. 
    1919 
    2020Validation du formulaire de connexion 
    2525Mais que doit-il se passer si l'utilisateur soumets des données incorrectes ? Pour gérer ce cas de figure, vous devez créer un fichier `login.yml` dans le répertoire `/frontend/modules/user/validate` (Notez que `login` est le nom de l'action dont le formulaire doit être validé). Ajouter le contenu suivant à ce fichier : 
    2626 
     27    [php] 
    2728    methods: 
    2829      post: [nickname, password] 
    4647Premièrement, sous l'entête `methods`, vous devez lister les champs à valider pour la méthode du formulaire (nous ne définissons ici que la méthode POST car les données GET ne sont utilisées que pour afficher le formulaire et n'ont pas besoin d'être validée). 
    4748Puis, sous l'entête `names`, les critères de validation de chaque champs à valider sont listés, suivi du message d'erreur correspondant. 
    48 Eventuellement, à l'image du champs `nickname`, il est possible de définir des règles de validation spécifiques, sous l'entête correspondant au nom de cette règle. Dans cet exemple, le `sfStringValidator` est un validateur proposé par symfoy qui valide le format d'une chaine de caractères (les validateurs par défaut proposés par Symfony sont détaillés dans le chapitre exposant [comment valider un formulaire] (http://www.symfony-project.com/book/1_0/10-Forms) dans le livre Symfony) 
     49Eventuellement, à l'image du champs `nickname`, il est possible de définir des règles de validation spécifiques, sous l'entête correspondant au nom de cette règle. Dans cet exemple, le `sfStringValidator` est un validateur proposé par symfoy qui valide le format d'une chaîne de caractères (les validateurs par défaut proposés par Symfony sont détaillés dans le chapitre exposant [comment valider un formulaire] (http://www.symfony-project.com/book/1_0/10-Forms) dans le livre Symfony) 
    4950 
    5051### Gestionnaire d'erreur 
    5152 
    52 Maintenant, qu'est-il sensé se passer si un utilisateur valide des données invalides ? Les conditions écrites dans le fichier `login.yml` ne seront pas satisfaites, et le controleur de symfony va transmettre la requête à la méthode `handleErrorLogin` de la classe `userActions` - à l'image de la méthode `executeLogin()`, tel que défini dans l'argument de la balise `form_tag`. 
     53Maintenant, qu'est-il censé se passer si un utilisateur valide des données invalides ? Les conditions écrites dans le fichier `login.yml` ne seront pas satisfaites, et le contrôleur de symfony va transmettre la requête à la méthode `handleErrorLogin` de la classe `userActions` - à l'image de la méthode `executeLogin()`, tel que défini dans l'argument de la balise `form_tag`. 
    5354Si cette méthode n'existe pas, le comportement par défaut est d'afficher le template `loginError.php`. La raison de ce comportement est que la méthode `handleError()` d'origine retourne : 
    5455 
    55 [php] 
    56 public function handleError() 
    57 
    58   return sfView::ERROR; 
    59 
    60   
    61 Nous avons un nouveau gabarit à écrire. Or, il serait préférable de ré-afficher le formulaire de connexion , avec les messages d'erreur affichés près des champs invalides. Donc, nous allons modifier le comportement de l'erreur de connexion pour afficher le template `loginSuccess.php` en cas d'erreur. 
    62  
    63 [php] 
    64 public function handleErrorLogin() 
    65 
    66   return sfView::SUCCESS; 
    67 
     56    [php] 
     57    public function handleError() 
     58   
     59      return sfView::ERROR; 
     60   
     61  
     62Nous avons un nouveau gabarit à écrire. Or, il serait préférable de ré-afficher le formulaire de connexion, avec les messages d'erreur affichés près des champs invalides. Donc, nous allons modifier le comportement de l'erreur de connexion pour afficher le template `loginSuccess.php` en cas d'erreur. 
     63 
     64    [php] 
     65    public function handleErrorLogin() 
     66   
     67      return sfView::SUCCESS; 
     68   
    6869  
    6970>**NOTE** 
    7071>La convention de nommage qui lie le nom de l'action, sa valeur de retour et le nom du fichier template est détaillée dans le [chapitre concernant la couche "Vue"] (http://www.symfony-project.com/book/1_0/07-Inside-the-View-Layer) du livre Symfony 
     72 
     73### Les helpers d'affichage des erreurs 
     74 
     75Il est désormais temps d'afficher les erreurs dans le template `loginSuccess.php`. Pour cela, nous allons utiliser le helper `form_error()` de la librairie de helpers `Validation`, prévue à cet effet. Remplacez les deux div `form_row` du templates par le code suivant : 
     76 
     77    [php] 
     78    <?php use_helper('Validation') ?> 
     79     
     80    <div class="form-row"> 
     81      <?php echo form_error('nickname') ?> 
     82      <label for="nickname">nickname:</label> 
     83      <?php echo input_tag('nickname', $sf_params->get('nickname')) ?> 
     84    </div> 
     85      
     86    <div class="form-row"> 
     87      <?php echo form_error('password') ?> 
     88      <label for="password">password:</label> 
     89      <?php echo input_password_tag('password') ?> 
     90    </div> 
     91  
     92Le helper `form_helper()` à pour comportement d'afficher le message d'erreur défini dans le fichier `login.yml` si une erreur est détectée dans le champ défini en paramètre. 
     93 
     94Il est temps de tester la validation du formulaire en essayant de saisir un valeur de moins de 5 caractères dans le champs `nickname`, ou alors en ne remplissant pas l'un des champs. Le message d'erreur apparaît juste au dessus du champ concerné : 
     95 
     96![Erreur dans le formulaire de connexion] (http://www.symfony-project.org/images/askeet/1_0/login_form_error.gif) 
     97 
     98Le mot de passe est désormais obligatoire, mais aucun mot de passe n'est présent en base de données ! Pas d'inquiétude, quel que soit le mot de passe que vous saisissiez, la connexion fonctionnera, pour un peu que le login existe en base de données. Ce n'est pas très sécurisé, n'est-ce pas ? 
     99 
     100### Style des message d'erreur 
     101 
     102Si vous avez testé le formulaire et obtenu une erreur, vous avez sûrement remarqué que cette erreur n'est pas affichée comme dans l'image présentée. La raison est que nous avons défini le style de la classe `.form_error_class` (dans le fichier `web/main.css`), qui est la classe par défaut associée aux champs générés par le helper `form_error()`: 
     103 
     104    [php] 
     105    .form_error 
     106    { 
     107      padding-left: 85px; 
     108      color: #d8732f; 
     109    } 
     110 
     111Authentifier un utilisateur 
     112--------------------------- 
     113 
     114### Validateur personnalisé 
     115 
     116Vous rappelez vous la vérification d'hier, concernant l'existence du nickname saisie dans l'action `login` ? Cette vérification ressemble à la validation d'un formulaire. Ce code pourrait être placé en dehors de l'action et inclus dans un validateur personnalisé. Vous pensez que c'est compliqué ? On ne peut pas dire ça. Editez le fichier de validation `login.yml` et modifiez son contenu de la sorte : 
     117 
     118    [php] 
     119    ... 
     120    names: 
     121      nickname: 
     122        required:      true 
     123        required_msg:  your nickname is required 
     124        validators:    [nicknameValidator, userValidator] 
     125    ... 
     126    userValidator: 
     127        class:         myLoginValidator 
     128        param: 
     129          password:    password 
     130          login_error: this account does not exist or you entered a wrong password 
     131 
     132Nous venons d'ajouter un nouveau validateur au champ `nickname`, basé sur la classe `myLoginValidator`. Cette classe n'existe pas encore, mais nous savons qu'il lui faudra le password pour complètement valider l'authentification d'un utilisateur, nous le transmettons donc en paramètre sous le label `password` 
     133 
     134### Stockage du mot de passe 
     135 
     136Mais attendez une minute. Dans notre modèle de données, autant que dans les données de test, aucun mot de passe n'est défini. Il est donc temps de le définir. Mais vous devez savoir que stocker un mot de passe en clair, dans une base de données, est une très mauvaise idée pour des raisons de sécurité. Nous allons donc stocker une [version hashé par sha1] (http://en.wikipedia.org/wiki/SHA_hash_functions) du mot de passe, ainsi que la clé aléatoire utilisée pour le hasher. Si vous n'êtes pas familier avec ce principe de 'sel', consultez les [techniques de crackage de mot de passe] (http://en.wikipedia.org/wiki/Password_cracking). 
     137 
     138Ouvrez le fichier `schema.xml` et ajouter les colonnes suivantes dans la table `User` : 
     139 
     140    [php] 
     141    <column name="email" type="varchar" size="100" /> 
     142    <column name="sha1_password" type="varchar" size="40" /> 
     143    <column name="salt" type="varchar" size="32" /> 
     144 
     145Re-génerez le modèle de données Propel via la commande `symfony propel-build-all`. Vous auriez également pu ajouter les 2 colonnes à la base de données, soit manuellement, soit en utilisant le fichier `lib.model.schema.sql` généré à la suite de l'exécution de la commande `symfony propel-build-sql`. Editez maintenant le fichier `askeet/lib/model/User.php` et ajouter cette méthode `setPassword()` : 
     146 
     147    [php] 
     148    public function setPassword($password) 
     149    { 
     150      $salt = md5(rand(100000, 999999).$this->getNickname().$this->getEmail()); 
     151      $this->setSalt($salt); 
     152      $this->setSha1Password(sha1($salt.$password)); 
     153    } 
     154  
     155Cette fonction simule un stockage direct du mot de passe, mais effectue réellement la génération d'une clé aléatoire `salt` (une chaîne de 32 caractères hashé) et le mot de passe hashé (une chaîne de 40 caractères). 
     156 
     157### Ajouter le mot de passe dans les données de test 
     158 
     159Vous rappelez vous le fichier de données de test du [troisième jour] (http://trac.symfony-project.com/wiki/Documentation/fr_FR/askeet/trunk/D3) ? Il est temps d'ajouter un mot de passe et un email aux données de test. Ouvrez et modifiez le fichier `askeet/data/fixtures/test_data.yml` comme suit : 
     160 
     161    [php] 
     162    User: 
     163      ... 
     164      fabien: 
     165        nickname:   fabpot 
     166        first_name: Fabien 
     167        last_name:  Potencier 
     168        password:   symfony 
     169        email:      fp@example.com 
     170     
     171      francois: 
     172        nickname:   francoisz 
     173        first_name: François 
     174        last_name:  Zaninotto 
     175        password:   adventcal 
     176        email:      fz@example.com 
     177 
     178Comme la méthode `setPassword()` a été définie dans la classe `User`, l'objet `sfPropelData` remplira correctement les nouvelles colonnes `sha1_password` et `salt` définies dans le schéma lors de l'appel au script de population des données : 
     179 
     180    $ php batch/load_data.php 
     181 
     182>**NOTE** 
     183> Notez que le l'objet sfPropelData est capable d'utiliser des méthodes qui ne correspondent pas à des colonnes réelles du modèle de données (Et voilà, nous dépassons les capacités du SQL traditionnel !) 
     184> 
     185> Si vous vous demandez comment c'est possible, vous n'avez qu'a jetez un coup d'oeil dans [le chapitre de population de base de données] (http://www.symfony-project.com/book/1_0/08-Inside-the-Model-Layer) du livre symfony 
     186> 
     187> Note: Le fait de ne pas définir de mot de passe pour l'utilisateur 'Anonymous Coward' permet d'interdire la connexion avec ce compte. De plus, ne tentez pas de vous connecter sur le site public Askeet avec les mots de passes donnés en exemple, il est évident que nous ne donnons pas les vrais mots de passe. 
     188 
     189Validateur personnalisés 
     190------------------------ 
     191 
     192Maintenant, il est temps de définir le validateur `myLoginValidator`. Vous pouvez créer cette classe `myLoginValidator.class.php` dans n'importe quel dossier `lib/` accessible par le module (c'est à dire, pour le cas présent, dans `askeet/lib/`, ou dans `askeet/apps/frontend/lib/`, ou encore dans `askeet/apps/frontend/modules/user/lib/`). Dans le cas présent, le validateur est considéré comme pouvant être utile à toute l'application, et sera donc créé dans le dossier `askeet/apps/frontend/lib/` : 
     193 
     194    [php] 
     195    <?php 
     196      
     197    class myLoginValidator extends sfValidator 
     198    {     
     199      public function initialize($context, $parameters = null) 
     200      { 
     201        // initialize parent 
     202        parent::initialize($context); 
     203      
     204        // set defaults 
     205        $this->setParameter('login_error', 'Invalid input'); 
     206      
     207        $this->getParameterHolder()->add($parameters); 
     208      
     209        return true; 
     210      } 
     211      
     212      public function execute(&$value, &$error) 
     213      { 
     214        $password_param = $this->getParameter('password'); 
     215        $password = $this->getContext()->getRequest()->getParameter($password_param); 
     216      
     217        $login = $value; 
     218  
     219        // anonymous is not a real user 
     220        if ($login == 'anonymous') 
     221        { 
     222          $error = $this->getParameter('login_error'); 
     223          return false; 
     224        } 
     225      
     226        $c = new Criteria(); 
     227        $c->add(UserPeer::NICKNAME, $login); 
     228        $user = UserPeer::doSelectOne($c); 
     229      
     230        // nickname exists? 
     231        if ($user) 
     232        { 
     233          // password is OK? 
     234          if (sha1($user->getSalt().$password) == $user->getSha1Password()) 
     235          { 
     236            $this->getContext()->getUser()->setAuthenticated(true); 
     237            $this->getContext()->getUser()->addCredential('subscriber'); 
     238      
     239            $this->getContext()->getUser()->setAttribute('subscriber_id', $user->getId(), 'subscriber'); 
     240            $this->getContext()->getUser()->setAttribute('nickname', $user->getNickname(), 'subscriber'); 
     241      
     242            return true; 
     243          } 
     244        } 
     245      
     246        $error = $this->getParameter('login_error'); 
     247        return false; 
     248      } 
     249    } 
     250  
     251Lorsque le validateur est appelé - après la validation du formulaire de connexion - la méthode `initialize()` est tout d'abord appelée. Cette méthode initialise la valeur par défaut du message `login_error` ('Invalid input') et ajoute les paramètres du validateur (ceux qui se trouvent sous l'entête `param:` dans le fichier `login.yml`) dans l'objet de collecte des paramètres. 
     252 
     253Puis la méthode `execute()` est ... exécutée. La variable `$password_param` contient la valeur définie dans le fichier `login.yml` sous l'entête `password`. Cette variable est utilisée pour récupérer une valeur dans les paramètres transmis. Donc, la variable `$password` contient le mot de passe saisi par l'utilisateur. La variable `$value` contient la valeur du champ courant - et la classe `myLoginValidator` est appelée pour le champ `nickname`. La variable `$login` contient donc le nickname saisi par l'utilisateur. Désormais, nous avons toutes les données nécessaires pour que le validateur puisse valider un utilisateur. 
     254 
     255Ce code remplace un code existant de l'action `login`. En outre, le test de validité du mot de passe (qui était précédement toujours vrai) est implémenté : un hashage du mot de passe saisi par l'utilisateur (en utilisant le sel stocké en base de données) est comparé au mot de passe hashé de l'utilisateur. 
     256 
     257Si le login et le mot de passe sont correct, le validateur retourne `true` et l'action associée au formulaire (`executeLogin()`) sera exécutée. Sinon, il retourne `false` et c'est la fonction `handleErrorLogin()` qui sera exécutée.