Salut tout le monde,

J'ai commencé il y a quelques temps mon premier projet sur la 2.0, ceci après une longue période de non-utilisation de Cake, et je dois dire que c'est vraiment pas mal du tout.

Cela étant, je fais face à quelques problèmes, notamment pour le validate.

Je bosse actuellement sur mon premier model, User, et j'ai déjà établi quelques règles simples :

  • le nom d'utilisateur doit être unique, ne doit pas être vide, et est alphanumeric.
  • l'email doit être un email et ne dois pas être vide.
  • le password ne doit pas être vide et doit faire 8 caractères minimum.

Donc jusqu'ici tout va bien, la méthode validate n'a pas changé du tout. De plus, chacune des différentes règles dispose d'un message particulier et le paramètre last est à true.
En revanche, c'est dans ce qui en ressort que j'ai quelques soucis.

J'utilise validates() vu que l'inscription se fait en Ajax, et je suis assez déstabilisé par la valeur et le tableau qui me sont retournés. Je passe à invalidFields le paramètre fieldList qui contient un seul champ (celui que je vérifie on keyup en ajax).

Quand tout va bien, effectivement, on me retourne true et invalidFields est vide.

En revanche, quand il y a une erreur, c'est le chaos.
Dans le cas où la chaîne n'est pas valide (donc un false sur alphanumeric, ou email), le message d'erreur est retourné 2 fois, et un autre champ est vérifié lui aussi...

Par exemple si je tape comme nom d'utilisateur "(-)Pakito(-)", l'array renvoyé est du genre :

array (
    [username] => array(
        [0] => 'Le nom d\'utilisateur n\'est pas valide',
        [1] => 'Le nom d\'utilisateur n\'est pas valide'
    )
    [email] => array(
        [0] => 'L\'email n\'est pas valide'
    )
)

Totalement aberrant quand on sait que lorsque j'initialise User, les données que je lui passe ne comporte toujours qu'un seul et unique champ... Qui plus est, champ précisé par fieldList.

Dans le cas où c'est une condition différente (isUnique, minlenght, etc...), invalidFields renvoie bien false, mais aucun message d'erreur. Même pas un array vide, rien. Pourtant les règles sont bien testées puisque le moteur renvoie false, et les messages sont bien spécifiés dans mon Model.

Après y avoir passé une partie de la nuit, je sèche un peu... De plus, je ne comprends pas non plus que les valeurs du tableau des erreurs soient contenues dans des index numériques alors qu'on spécifie un nom de règle dans le Model.
Si ça renvoyait :

array(
    [username] => array(
        [unique] => 'Ce nom d\'utilisateur n\'est pas disponible'
    )
)

ce serait nettement plus propre, d'une part, mais cela permettrait de gérer les erreurs de façon différente.
Pour exemple, dans le cas présent, je gère le format et le fait que le champ soit requis et non vide par un message ajouté à une div #error, mais en revanche, si le pseudo n'est pas disponible, je mets à jour le div #dispo.

Bref, j'ai cherché, dans la doc, dans les forums officiels, en anglais, en français, et rien.
Pourtant il n'y a pas d'erreur, puisque les critères sont bien appliqués avant un save. De même, le true/false d'invalidFields est bon.

Je sèche, et je m'en remets à vous ;)

14 réponses


Pakito
Auteur
Réponse acceptée

... Du gros, du très gros lol. Je viens de réussir à faire parvenir le code après 10 vérifications de mon model, de mon controller, de mon js.

Jusqu'ici, je me contentais de debug($errors); qui selon toute vraisemblance retourne un array contenant la ou les erreurs.
Et jusqu'ici, je n'étais pas allé plus loin parce que dans le cas de isUnique, l'array était vide.

Je viens de remplacer :

if ($this->User->validates(array('fieldList' => array($this->request->data'champ'])))) {
                echo('<p class="succes">Ce pseudo est disponible.</p>');
            } else {
                echo('<p class="erreurs">Ce pseudo n\'est pas disponible.</p>');
                $errors = $this->User->invalidFields(array('fieldList' => array($this->request->data'champ'])));
                debug($errors);
            }

Par ton code :

$champ = $this->request->data'champ'];
            $errors = $this->User->invalidFields();
                if (array_key_exists($champ,$errors)){
                    echo ($errors$champ][0]);
                }else{
                        echo ("1");
                    }

Et miracle, ça fonctionne. Mais mieux que ça : j'ai identifié mon erreur. Parce qu'après avoir constaté que ça fonctionnait avec ton code, mais avec des erreurs d'encodage sur les accents, j'ai choisi de debug $errors à nouveau, et là, même résultat : vide.

Réflexion faite, il est impossible de retourner la valeur d'une variable vide, ça tombe sous le sens.
Puis j'ai repensé à l'encodage des accents qui était foiré. J'ai converti mon model en UTF-8, et visiblement, il ne l'était pas avant, je ne sais pourquoi. Peut-être le passage de Notepad++ en UTF-8 Sans BOM à Sublime Text a-t-il semé le chaos. Toujours est-il qu'avec un encodage correct, tout est niquel.

Va savoir pourquoi les autres règles étaient passées sans problème par contre...

En tout cas merci de ton aide ;)

Oui donc tu cherche seulement à récupérer le message d'erreur ?

$errors = $this->User->invalidFields();
                if (array_key_exists($champ,$errors)){
                    echo ($errors$champ][0]);
                }else{
                        echo true;
                    }

Comme ça j'ai un true si le field est bon et le message dans le cas ou ce n'est pas bon

Pakito
Auteur

Oui mais justement, quand on debug $errors, il est vide dans le cas d'un isUnique, par exemple. Et sinon, il est fourni bizarrement, même avec fieldList...

Non moi j'ai pas le cas pour isUnique j'ai bien mon message d'erreur.

Voici mon $validate :

public $validate = array(
        'username' => array(
            array(
                'rule' => 'alphanumeric',
                'required' => true,
                'allowEmpty' => false,
                'message' => "Votre pseudo n'est pas valide",
                ),
            array(
                'rule' => 'isUnique',
                'message' => "Ce pseudo est déja utilisé",
                ),
        ),      
        'mail' => array(
            array(
                'rule' => 'email',
                'required' => true,
                'allowEmpty' => false,
                'message' => "Votre mail n'est pas valide",
                ),
            array(
                'rule' => 'isUnique',
                'message' => "Ce mail est déja utilisé",
                ),
        ),      
        'password' => array(
                array(
                    'rule' => 'notEmpty',
                    'message' => "Vous devez entrer un mot de passe",
                    'allowEmpty' => false),
                array('rule' => 
                array('minLength', '6'),
                    'message' => '6 Caractère minimum') 
        ),
    );
Pakito
Auteur

Je viens de copier ton code, ligne pour ligne, en renommant juste 'mail' par 'email', mais rien à faire : j'ai toujours un invalidFields vide pour les isUnique, même pas un array vide hein, il n'y a rien de retourné. Et pourtant, validates() renvoie false.

Pour le minLenght du mot de passe, ça marche par contre.

Comme tu peux le voir cela fonctionne :/

Voici mon mon js

function validation(value, champ, controller) {
        $.ajax({
            async:true,
            type:'post',
            complete:function(request, json) {
                if (request.responseText != "1"){
                    $('#'+champ).removeClass("validate_success");
                    $('#'+champ).addClass("validate_error");
                    $('#'+champ+'+ .error.small' ).remove();
                    $('#'+champ).after("<p class='error small'><span class='icon error'></span>"+request.responseText+"</p>");
                    return false;
                }                       
                else {
                    $('#signup + .error.small' ).remove();
                    $('#'+champ+'+ .error.small' ).remove();
                    $('#'+champ).removeClass("validate_error");
                    $('#'+champ).removeClass("tip-stay");
                    $('#'+champ).addClass("validate_success");
                    return true;
                };
            },
            url: '/'+controller+'/validation',
            data: {champ: champ, valeur: value}
        });
    }
$('input.validation').live('keyup', function(){
                var champ = $(this).attr('id');
                var value = $(this).val();
                var controller = $(this).parents('form').attr('id').split('-');
                var controller = controller[0];
                if (value.length > 0) {
                    validation(value, champ, controller);
                }else{
                    $('#'+champ).removeClass("validate_success");
                    $('#'+champ).addClass("validate_error");
                }
        });
Pakito
Auteur

Et tu as quoi dans ton controller ?
Parce que pour l'instant, ma fonction validation() (en cours de création donc, et bloquée par ce soucis) se résume à cela :

public function validation() {
        if($this->request->is('ajax')) {
            $ajax_data = array($this->request->data'champ'] => $this->request->data'valeur']);
            $d'user'] = $ajax_data;
            $this->User->create($ajax_data);
            $this->set($d);

            if ($this->User->validates(array('fieldList' => array($this->request->data'champ'])))) {
                echo('<p class="succes">Ce pseudo est disponible.</p>');
            } else {
                echo('<p class="erreurs">Ce pseudo n\'est pas disponible.</p>');
                $errors = $this->User->invalidFields();
                debug($errors);
            }
        }
    }

L'idée, quand ça marchera, c'est de retourner 2 variables en json :

  • Si la condition est validée (true / false)
  • Le message d'erreur s'il y en a un, sinon un message de succès

Au niveau du js je n'ai pas de soucis puisque la requête est bien effectuée, et en cas d'erreur, elle est bien affichée, et $errors contient bien un tableau avec le message.
Le truc c'est qu'il ne génère rien pour isUnique. Je précise que dans ma BDD, les champs email et username ont l'index UNIQUE.

public function validation() {
        if($this->request->is('ajax')){
            $this->autoRender = false;
            $ajax_data = array($this->request->data'champ'] => $this->request->data'valeur']);
            $champ = $this->request->data'champ'];
            $d'user'] = $ajax_data;
            $this->User->create($ajax_data);
            $errors = $this->User->invalidFields();
                if (array_key_exists($champ,$errors)){
                    echo ($errors$champ][0]);
                }else{
                        echo ("1");
                    }
        }

    }

Si il y a une erreur : je renvoi le message d'erreur.
Si il n'y en a pas je renvoi un 1 :) que je traite apres dans mon js

Pakito
Auteur

D'accord, et bien je ne vois pas ce qui ne colle pas dans le mien. Tout fonctionne, c'est juste que le message n'est pas renvoyé pour isUnique...

Envoie ton $validate pour voir meme si je pense pas que tu as fais d'erreur

Pakito
Auteur
public $validate = array(
        'username' => array(
            'pas_vide' => array(
                'rule' => 'notEmpty',
                'AllowEmpty' => false,
                'required' => true,
                'message' => 'Ce champ est obligatoire',
                'last' => true
            ),
            'format' => array(
                'rule' => 'alphanumeric',
                'message' => 'Votre pseudo ne peut contenir que des lettres et des chiffres',
                'last' => true
            ),
            'unique' => array(
                'rule' => 'isUnique',
                'message' => 'Ce pseudo est déjà pris',
                'last' => true
            )
        ),
        'email' => array(
            'format' => array(
                'rule' => 'email',
                'required' => true,
                'AllowEmpty' => false,
                'message' => 'Votre email n\'est pas valide'
            ),
            'unique' => array(
                'rule' => 'isUnique',
                'message' => 'Cet email est déjà pris'
            )
        ),
        'password' => array(
            'pas_vide' => array(
                'rule' => 'notEmpty',
                'message' => 'Vous devez entrer un mot de passe',
                'AllowEmpty' => false
            ),
            'minimum' => array(
                'rule' => array('minLength', 8),
                'message' => 'Le mot de passe doit comporter au moins 8 caractères'
            )
        )
    );

Voila. Mais le pire c'est que ça ne fonctionne toujours pas alors que je me sers du tiens.
Niveau BDD, comment sont configurés les champs que tu teste avec isUnique ?
Edit : j'ai essayé avec et sans index unique dans la bdd, et ça ne change rien. Je désespère.
Tu es bien sur Cake 2 ?

Désolé , j'ai mis mon temps :D

Oui bien sur je suis sur cake2.
Configurer normalement, meme pas d'index ou de unique dans mysql. J'ai laissé cakephp le réaliser.
Je viens d'activer le unique pour mon champs username est ca marche toujours :)
File moi ton mail, tu vas m'envoyer les fichiers et je vais voir si ca me fait le meme bug :)

ba voila :)
résolu :D

Pakito
Auteur

Ouep ! :)