Zend FR

Consultez la FAQ sur le ZF avant de poster une question

Vous n'êtes pas identifié.

#1 12-02-2009 12:34:25

cortex
Membre
Date d'inscription: 22-05-2008
Messages: 33

[ZendX_JQuery] Validation de formulaire

Bonjour,

Je suis à la recherche d'un composant afin de permettre l'intégration automatique de validateurs javascript depuis un formulaire Zend_Form se basant sur ce plugin JQuery http://bassistance.de/jquery-plugins/jq … alidation/
J'en ai cherché d'autres mais il me semble que ce soit le plus complet.

Pour ce plugin, la configuration des validateurs est faite soit par un appel paramétré, soit par lecture de metadata directement sur les champs inputs. La deuxième solution bien qu'alléchante propose moins de fonctionnalité, notamment sur le paramétrage des messages d'erreurs ou alors je n'ai pas trouvé (et j'aime pas trop cette approche intrusive).
Sans entrer dans les détails avec les messages et autres options, le code js ressemble à quelques choses commes ça

Code:

$("#form-validate").validate({
    "rules": {
        "account_subdomain": {
            "remote":"\/users.php",
            "required":true },
        "account_email": {
            "email":true,
            "required":true },
        "account_date": {
            "date":true,
            "required":true }
}});

Mon idée est donc de créer un Zend_Form et d'y ajouter des éléments et celui-ci automatiquement va ajouter l'appel javascript paramétré qui va bien pour tout ses éléments.

Mes recherches et tests hier soir m'ont conduit à ceci:
- J'ai créer une classe dérivée de ZendX_JQuery_Form (ou de Zend_Form avec un ZendX_JQuery::enableForm($this))
- J'ai surchargé la méthode createElement afin d'ajouter un custom decorator en début de chaîne à chaque élément ajouté par config.

Ce custom decorator récupère les options/attributs du Zend_Element et remplit un container avec les paramètres qu'il trouve (il est capable de sortir la valeur de required, aller chercher les validateurs et sur ceux connus et en commun avec le plugin JQuery de générer ce qu'il faut comme paramètre et messages). Pour le custom, j'utilise un attribut spécifique, l'idée étant de ne pas s'en servir, tout doit être déduit des éléments.

Le container pour le moment est géré par un simple view helper. Dans mon header, j'ai quelque chose comme :

Code:

<?= $this->jQueryValidation() ?>
<?= $this->jQuery() ?>

Mon helper jQueryValidation ne fait aucun rendu dans la méthode __toString(), il récupère le tableau de paramètre alimenté par les décorateurs, le transforme en JSon et fait un $view->jQuery()->addOnLoad('$("#form-validate").validate(' . $json . ')).


Cela marche pas trop mal mais :
- Je voudrais ne pas avoir mon view helper, il faudrait que ça soit le Zend_Form qui fasse le addOnLoad. Comment puis-je faire cela ?

- Je ne sais pas dans le décorateur récupérer la classe Zend_Form de l'élément. En effet, si j'ai plusieurs formulaire dans une page, le container est global pour le moment car je ne connais pas l'id du formulaire. c'est d'ailleurs pour ça qu'il est en dur (#form-validate) car même passé en argument du helper ça ne résoud pas le problème de quand il y en a plusieurs (les décorateurs vont alimenté un unique container).

- Avoir une sous classe pour profiter de la validation JQuery n'a pas l'air top, car je ne pourrais pas ajouter cette fonctionnalité à de l'existant facilement. Est-ce qu'on peut passer sur chaque élément après création du formulaire pour modifier la collection des décorateurs ? Dans ce cas, une méthode statique un peu comme le enableForm de ZendX_JQuery serait sympa (ZendX_JQuery_FormValidation::enableValidation($form))

- Le fait de rajouter un décorateur, ne peut-il pas poser des problèmes avec des Zend_Element particulier ? J'ai testé avec text, datePicker (Jquery), textArea.

- Est-ce qu'il existe déjà quelque chose qui fasse ça ?


cortex

Dernière modification par cortex (14-02-2009 03:19:43)

Hors ligne

 

#2 12-02-2009 15:15:46

cortex
Membre
Date d'inscription: 22-05-2008
Messages: 33

Re: [ZendX_JQuery] Validation de formulaire

Un petit moment de libre, j'ai écrit ceci dans un draft :

[EDIT]: J'ai supprimé le code qui a été corrigé et reporté dans le post suivant.

Le décorateur est commun au formulaire et aux éléments. Plus de problème de conteneur multiple.

Bien entendu, le addClientValidation doit être appelé après que le formulaire ait été complètement construit.

Je vous tiens au courant si ça marche.

Dernière modification par cortex (14-02-2009 03:24:02)

Hors ligne

 

#3 12-02-2009 22:07:41

cortex
Membre
Date d'inscription: 22-05-2008
Messages: 33

Re: [ZendX_JQuery] Validation de formulaire

Bonne nouvelle dans le principe ça fonctionne bien, même très bien.

Par contre, j'en appelle à vos idées lumineuses sur un soucis d'implémentation pour extraire les validateurs. En effet, tester sur le isRequired est simple. Mais après, je voudrais un moyen élégant de "convertir" les validateurs du framework en paramètre JQuery.
Pour l'instant, je fais ça au coup par coup comme suit

Code:

            if($validator instanceof Zend_Validate_StringLength)
            {
                $params['rules']['rangelength'] = array($validator->getMin(), $validator->getMax());
            }
            else if($validator instanceof Zend_Validate_Digits )
            {
                $params['rules']['digits'] = true;
            }
            else if($validator instanceof Zend_Validate_EmailAddress )
            {
                $params['rules']['email'] = true;
            }

ce qui est loin d'être maintenable et franchement pas sympathique du tout. Malheureusement, je n'ai pas d'idée lumineuse, les validateurs sont tous différents, et aucun ne permet de récupérer ces paramètres.

Par ailleurs, pour les validateurs très particuliers, j'ai rajouté la possibilité de définir les paramètres directement au niveau de l'élément par l'attribut 'jQueryFormValidators'
Ainsi, on peut ajouter un élément comme ça:

Code:

$form->addElement('text', 'nom',  array(
    'validators' => array(
        array( 'stringLength', false, array( 1, 45 )),
        array('AccountNotExists', false, array( $this->id ))
        ),
    'required' => true,
    'label' => 'Nom',
    'size' => 45,
    'prefixPath' => array( Zend_Form_Element::VALIDATE  => array('prefix' => 'Freeh_Validate', 'path' => 'Freeh/Validate')),
    'jQueryFormValidators' => array(
        'rules' => array('remote' => '/account/validate/account/account_type/' . $this->id),
        'messages' => array('remote' => utf8_encode('Ce nom est déjà pris'))
        ),
    ));

Dans cet exemple, le validateur fera un appel AJAX sur l'url donnée en paramètre pour vérifier que le nom n'existe pas (rule remote issu du jQueryFormValidators) et fera également un test sur la longueur qui devra être comprise entre 1 et 45 (rule rangelength issu du StringLength), et sur le fait que le champ est obligatoire (rule required issu du required).
Côté serveur, on retrouvera ces mêmes tests par le fonctionnement normal du Zend_Form et des validateurs.

Pour utiliser tout ça, vous créer un Zend_Form classiquement et dans le controller, vous pouvez faire quelques choses comme

Code:

$form = new Zend_Form(...);
$form->addElements(...);
$options = array('onkeyup' => false,);
Freeh_JQuery::addClientValidation($form, $options);
$this->view->form = $form;

Merci pour vos retours et vos idées pour améliorer la chose.
Axe d'amélioration :
- Ajouter un view_helper pour faire le addClientValidation dans la vue, c'est un choix qui la concerne et le controlleur ne devrait pas être au courant, enfin c'est mon avis.
- Trouver un moyen de généraliser la "conversion" des validateurs.

Le code complet


Code:

class Freeh_JQuery_Form_Decorator_Validator extends Zend_Form_Decorator_Abstract
{
    public function __construct($options = null){ $this->params = $options; }

    protected $params = array();

    public function render($content)
    {
        $element = $this->getElement();
        
        if($element instanceof Zend_Form)
        {
            if(count($this->params) > 0) {
            require_once "Zend/Json.php";
            $params = Zend_Json::encode($this->params);
            } else {
                $params = "{}";
            }

            $js = sprintf('%s("#%s").validate(%s);',
                ZendX_JQuery_View_Helper_JQuery::getJQueryHandler(),
                $element->getId(),
                $params
            );
            $element->getView()->JQuery()->addOnLoad($js);
        }
        if($element instanceof Zend_Form_DisplayGroup){ } // todo ??
        
        if($element instanceof Zend_Form_Element)
        {
            $this->extractParams($element); // extrait les paramètres et remplit $this->params;
        }
        
        return $content;
    }
    
    protected function extractParams(Zend_Form_Element $element)
    {
        $params = $element->getAttrib('jQueryFormValidators');
        
        if(!is_array($params))
            $params = array();

        if($element->isRequired())
        {
            $params['rules']['required'] = true;
        }
        foreach($element->getValidators() as $validator)
        {
            if($validator instanceof Zend_Validate_StringLength)
            {
                $params['rules']['rangelength'] = array($validator->getMin(), $validator->getMax());
            }
            else if($validator instanceof Zend_Validate_Digits )
            {
                $params['rules']['digits'] = true;
            }
            else if($validator instanceof Zend_Validate_EmailAddress )
            {
                $params['rules']['email'] = true;
            }
        }
        
        if(count($params) > 0) 
        {
            $this->params['rules'][$element->getName()] = isset($params['rules']) ? $params['rules'] : array();
            if(isset($params['messages']))
                $this->params['messages'][$element->getName()] = $params['messages'];
        }
        
        $element->setAttrib('jQueryFormValidators', null);
    }
}

et

Code:

<?php

class Freeh_JQuery
{
    
    public static function addClientValidation(Zend_Form $form, $options = null)
    {
        $form->addPrefixPath('Freeh_JQuery_Form_Decorator', 'Freeh/JQuery/Form/Decorator', 'decorator')
             ->addElementPrefixPath('Freeh_JQuery_Form_Decorator', 'Freeh/JQuery/Form/Decorator', 'decorator')
             ->addDisplayGroupPrefixPath('Freeh_JQuery_Form_Decorator', 'Freeh/JQuery/Form/Decorator');

        $jqueryValidator = new Freeh_JQuery_Form_Decorator_Validator($options);
        $form->addDecorator($jqueryValidator); // rendu à la fin
        
        $form->getView()->jQuery()
            ->addJavascriptFile('/js/jquery.validate.min.js')
            ->addJavascriptFile('/js/localization/messages_fr.js');
        
        
        // passe sur tout les items pour ajouter le decorateur en premier
        // ne doit pas marcher avec les subform et autres Zend_Element particulier.
        // Je n'ai pas d'exemple pour tester et trouver une solution le cas où ça ne marcherait pas.
        foreach ($form as $item) {
            $olds = $item->getDecorators();
            $item->clearDecorators();
            $item->addDecorator($jqueryValidator);
            $item->addDecorators($olds);
        }
    }
}

Le helper

Code:

// utilisé dans la vue : <?= $this->JQueryFormValidation($this->form, array('onkeyup' => false)) ?>
// ou $form est un Zend_Form classique dans lequel on aura pris soin d'ajouter des éléments et leur validateur
class Freeh_View_Helper_JQueryFormValidation extends Zend_View_Helper_Abstract
{
    public function JQueryFormValidation(Zend_Form $form, array $options = null)
    {
            Freeh_JQuery::addClientValidation($form, $options);
        return $form;
    }
}

Dernière modification par cortex (14-02-2009 03:28:49)

Hors ligne

 

#4 12-02-2009 23:58:32

cortex
Membre
Date d'inscription: 22-05-2008
Messages: 33

Re: [ZendX_JQuery] Validation de formulaire

J'ai rajouté le view helper au post précédent.

Il faut ne pas oublier de l'ajouter au chemin des helpers de la vue

dans le bootstrap

Code:

public function initView()
{
  $layout = Zend_Layout::startMvc($this->_config->layout);
  $view = $layout->getView();
  $view->addHelperPath('Freeh/View/Helper/', 'Freeh_View_Helper');
}

Dernière modification par cortex (12-02-2009 23:59:02)

Hors ligne

 

Pied de page des forums

Propulsé par PunBB
© Copyright 2002–2005 Rickard Andersson
Traduction par punbb.fr

Graphisme réalisé par l'agence Rodolphe Eveilleau
Développement par Kitpages