IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Zend Framework PHP Discussion :

Zend_form, chargement dynamique après soumission avec Ajax, avec contrôle des erreurs [ZF 1.11]


Sujet :

Zend Framework PHP

  1. #1
    Membre régulier Avatar de eaglesnipe
    Homme Profil pro
    Ingénieur Etudes et Développement
    Inscrit en
    Janvier 2008
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur Etudes et Développement
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Janvier 2008
    Messages : 75
    Points : 76
    Points
    76
    Par défaut Zend_form, chargement dynamique après soumission avec Ajax, avec contrôle des erreurs
    Bonjour à toutes et tous, et merci de l'aide que vous pourrez éventuellement m'apporter.

    Tout d'abord j'ai longuement hésité entre poster dans le forum Zend Framework ou dans celui d'Ajax, mais mon problème étant quand même fortement lié à Zend mon post a donc atterrit ici !

    Je suis en train de créer une page qui va contenir plusieurs formulaires, la validation du premier entraînant l'apparition du second, etc. C'est donc tout naturellement que j'effectue la soumission des formulaires via Ajax. Voici mon code :

    Initialisation de mon controller Planning
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class PlanningController extends  Zend_Controller_Action {
    
        public function init(){
            $ajaxContext = $this->_helper->getHelper('AjaxContext');
            $ajaxContext->addActionContext('on-order-form-submit', 'html')
                    ->initContext();
    
            if ($this->_request->isXmlHttpRequest()) {
                $this->_helper->layout->disableLayout();
            }
        }
    }
    Mon formulaire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    class Application_Form_Planning_OrderFamily extends Zend_Form{
        public function init() {
            $view = Zend_Layout::getMvcInstance()->getView();
            $this->setAttrib('id', 'orderFamilyForm')
                    ->setAction($view->baseUrl() . '/planning/on-order-form-submit')
                    ->setMethod(Zend_Form::METHOD_POST);
    
            $this->addElement('select', 'orderFamily', array(
                'Label' => 'Famille d\'intervention',
                'MultiOptions' => //...,
                'Required' => true
            ));
    
            $this->addElement('text', 'client', array(
                'Label' => 'Client',
                'Maxlength' => 10,
                'Size' => 10,
                'Required' => true,
                'Validators' => array(
                    new App_Validate_Client()
                )
            ));
    
            $this->addElement('submit', 'orderFamilySubmit', array(
                'label' => 'Générer'
            ));
        }
    }
    On constate donc que la soumission du formulaire s'effectue vers une autre action (->setAction($view->baseUrl() . '/planning/on-order-form-submit'))

    Mon action index qui va créer le premier formulaire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class PlanningController extends  Zend_Controller_Action {
        public function indexAction() {
            //...
            $this->view->formOrderFamily = new Application_Form_Planning_OrderFamily();
        }
    }
    Et la vue associée (du moins une partie)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    <div class="grid_24 alpha omega">
      <div id="planningProviderContainer" class="grid_7 alpha container">
        <h1 class="icon worldLink pngFix">Famille</h1>
        <?php echo $this->formOrderFamily; ?>
      </div>
     
      <div id="planningQueryContainer" class="grid_17 omega container">
      </div>
     
    </div>
    Mon action on-order-form-submit qui va être appelée à la soumission du formulaire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class PlanningController extends  Zend_Controller_Action {
        public function onOrderFormSubmitAction() {
            $form = new Application_Form_Planning_OrderFamily();
            $this->view->formOrderFamily = $form;
            if ($this->_request->isPost()){
                if ($form->isValid($this->_request->getPost())){
                    // Valide
                }
                else {
                    // Invalide
                }
            }
        }
    }
    A terme cette fonction va créer le nouveau formulaire et transmettre la réponse HTML au javascript qui se contentera de l'afficher.

    Et finalement mon javascript
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    $("#orderFamilyForm").submit(function(){
     
         // On récupère les paramètres
         var orderFamily = $('#orderFamilyForm #orderFamily option:selected').val();
         var client= $('#orderFamilyForm #client').val();
     
          // On lance notre requête Ajax
          $.ajax({
               type: 'POST',
               url: baseUrl + '/planning/on-order-form-submit',
               data: {
                    client: client,
                    orderFamily: orderFamily
                },
                success: function(data, status, jqXHR){
                     $('#planningQueryContainer').html(data);
                },
                error: function(jqXHR, status, error){
                      alert(error);
                },
                 dataType: 'html'
            });
     
            // On empêche le navigateur de soumettre le formulaire et
            //recharger la page
            return false;
    });
    Le problème qui se pose alors est le suivant : Comment tirer profit des validateurs Zend au travers de cette requête Ajax ?
    Lorsque le formulaire est correctement renseigné, parfait je vais pouvoir faire mes traitements, récupérer mon flux HTML (je travaille en HTML et non en JSON) et l'afficher là où il faut dans la page via Javascript.

    Mais si le formulaire contient des erreurs, comment alors récupérer le nouveau HTML qui contiendra le code du formulaire en erreur (et toute sa mise en page) pour venir le remplacer à sa position initiale ? Le problème qui se pose est que je réceptionne un flux HTML, je n'ai donc aucun moyen de positionner une variable pour savoir si tout s'est bien passer ou non.

    J'avais penser à faire en sorte de me retrouver dans la callback d'erreur Ajax via un

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    header('HTTP/1.1 400 Bad Request');
    lorsque le formulaire était erroné, mais dans ce cas je perd alors mon flux de données HTML (il n'y a pas de paramètre data dans cette callback) et n'ai alors aucun moyen de mettre à jour le premier formulaire en erreur...

    (Toutes mes excuses si je ne suis pas des plus clair...)

    J'ai également pensé dans ce cas, si dans la callback d'erreur, relancer une requête ajax vers une autre action qui elle sera en charge de me renvoyer le flux HTML du formulaire en erreur et je pourrai alors faire mon remplacement. Mais ça ne me parait pas propre du tout et bien bien lourd. Avez vous vous de meilleurs solutions, des suggestions ?

    Pour information contrairement au code montrer, ma vue du premier formulaire est bien isolée dans un partial, donc c'est simplement ce flux qu'il me faudrait récupérer si erreur du formulaire, pour remplacement, ou le flux (partial là aussi) du nouveau formulaire si le premier est correct, pour le mettre là où il faut.

    J'espère ne pas vous avoir trop assommé et merci pour votre éventuelle aide.

  2. #2
    Membre régulier Avatar de eaglesnipe
    Homme Profil pro
    Ingénieur Etudes et Développement
    Inscrit en
    Janvier 2008
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur Etudes et Développement
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Janvier 2008
    Messages : 75
    Points : 76
    Points
    76
    Par défaut
    Bonjour à tou(te)s !

    Je viens donner un peu quelques nouvelles concernant ce problème qui n'a semble-t-il pas inspiré beaucoup de monde !

    Je pense avoir trouvé une solution pour résoudre cette difficulté et suis en train de mettre en place le code qui va bien.

    Dès que tout sera au carré et propre, j'en ferai part ici pour ceux que ça pourrait intéresser !

    Voili Voilou !

    Bonne journée !

  3. #3
    Nouveau Candidat au Club
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2012
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2012
    Messages : 1
    Points : 1
    Points
    1
    Par défaut Une solution possible
    Bonjour,

    J'ai de mon côté trouvé une solution. Dans cette solution, j'utilise le $.post de jQuery:

    Dans mon formulaire, il y a 3 entrée : titre, et deux dates avec des validateurs non vides et dates qui retournent des messages d'erreur si il y en a.

    Code de l'action :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public function testAction(){
            $formulaire = new MonFormulaire();
        	$this->view->formulaire = $formulaire;
    }
    La vue :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    <?php echo $this->formulaire;?>
    <script type="text/javascript">
     
    var callback = function(data){
    	var response = jQuery.parseJSON(data);
    	if(response.error == 'true'){
    		alert(response.details);
    	}else{
    		alert('pas d\'erreur');
    	}
    }
     
     
    $(document).ready(function(){
    	$('#formulaire').submit(function(event) {		
    		event.preventDefault();
    		$.post('/moncontrolleur/testpost',
    				{ title : $('#formulaire #title').val(),
    				  date-start : $('#formulaire #date-start').val(),
    				  date-end : $('#newCampaign #date-end').val() },
    				callback);
    	});
    });
     
    </script>
    L'action qui récupère le post :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    public function testpostAction(){
     
        	$formulaire = new MonFormulaire();
     
        	if ($this->_request->isPost() && $formulaire->isValid($_POST) ){   
    			$this->view->response = Zend_Json::encode(array('error' => 'false'));
        	} else if ($this->_request->isPost()) {
        		$messages = $formulaire->processAjax($_POST);
        		$this->view->response = Zend_Json::encode(array('error' => 'true','details' => $messages));
        	}
        	Zend_Layout::resetMvcInstance();	// à utililser si tu as mis un Layout MVC par défault
    }
    puis enfin la vue de l'action testpost :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    <?php echo $this->response;?>
    Voilà!

  4. #4
    Expert éminent
    Avatar de GrandFather
    Inscrit en
    Mai 2004
    Messages
    4 587
    Détails du profil
    Informations personnelles :
    Âge : 54

    Informations forums :
    Inscription : Mai 2004
    Messages : 4 587
    Points : 7 103
    Points
    7 103
    Par défaut
    Bonjour,
    Citation Envoyé par eaglesnipe Voir le message
    Le problème qui se pose alors est le suivant : Comment tirer profit des validateurs Zend au travers de cette requête Ajax ?
    Lorsque le formulaire est correctement renseigné, parfait je vais pouvoir faire mes traitements, récupérer mon flux HTML (je travaille en HTML et non en JSON) et l'afficher là où il faut dans la page via Javascript.
    A priori tu as trouvé une solution à ton problème donc ma question ne sera que de pure forme, mais pourquoi tu n'utilises pas une même vue pour afficher tous les formulaires plutôt que d'utiliser des partials nécessitant chacun une requête Ajax spécifique ?

  5. #5
    Membre régulier Avatar de eaglesnipe
    Homme Profil pro
    Ingénieur Etudes et Développement
    Inscrit en
    Janvier 2008
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur Etudes et Développement
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Janvier 2008
    Messages : 75
    Points : 76
    Points
    76
    Par défaut
    Bonjour,

    @toumtam, merci pour ta réponse.

    Je prends un peu de temps pour expliquer la mienne, mais au final nos solutions se rapprochent énormément !

    Voici donc comment je gère tout le shmilblink :

    Tout d'abord dans mon init, je définis le contexte Ajax :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public function init() {
        $ajaxContext = $this->_helper->getHelper('AjaxContext');
        $ajaxContext->addActionContext('on-query-form-submit', 'json')
    }
    Le contexte défini qu'on travaille bien en flux Json et non HTML.

    Ensuite mon action qui crée mon formulaire. Ce dernier contient un input text avec un validateur perso pour vérifier sa cohérence (ainsi qu'un not null), une date avec validateur pour vérification de validité et quelques autres champs obligatoires.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    public function myAction() {
        //...
        // On créé le formulaire
        $this->view->queryForm = new Application_Form_Planning_Query();
    }
    Ma vue :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    <!-- ... -->
     
    <div id="planningQueryContainer" class="grid_17 omega container">
        <?php echo $this->render('planning/order-query.phtml'); ?>
    </div>  
    <div id="slots-view">
    </div>
     
    <!-- ... -->
    Sachant que planning/order-query.phtml est un partial pour afficher le formulaire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    <?php if ($this->renderQuery): ?>
        <h1>Critères </h1>
        <?php echo $this->queryForm; ?>
    <?php endif; ?>
    Mon javascript pour gérer la soumission du formulaire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    function onSubmitFormQuery()
    {
        $("#queryForm").submit(function(){
     
            var $form = $("#queryForm");
            var $zoneForm = $('#planningQueryContainer');
            var $zone = $('#slots-view');
     
            var params = $form.serialize();
     
            $.post(baseUrl + '/planning/on-query-form-submit/format/json', params, function(data){
                if(data.hasErrors){
                    // On remplace par le nouveau flux du formulaire (avec ses erreurs)
                    $zoneForm.html(data.form);
                } else {
                    // On affiche les nouvelles données dans la nouvelle zone
                    $zone.html(data.blabla);
                }
            });
     
            return false;
        });
    }
    On constate que par rapport aux éventuelles erreurs retournées, soit je me contente de réafficher le formulaire (avec donc ses erreurs) dans sa zone initiale (#planningQueryContainer), ou —si pas d'erreurs— j'affiche la réponse dans le container qui va bien (ici #slots-view)

    $form.serialize() me permet quant à lui de récupérer tous les champs du formulaire et construire la chaine de caractère du type
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    "champ1=val1&champ2=val2&champ3=val3..."
    afin de la passer en paramètre, sans avoir à récupérer les valeurs une à une à la main.

    L'action qui est en charge de récupérer le post du formulaire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    public function onQueryFormSubmitAction() {
            if ($this->_request->isPost()) {
                $this->view->hasErrors = false;
                $this->view->renderQuery = true;
     
                // On reconstruit le formulaire de saisie des critères pour vérifier s'il
                //est valide
                $this->view->queryForm = new Application_Form_Planning_Query();
                if ($this->view->queryForm->isValid($this->_request->getPost())) {
                    // S'il est valide, on effectue les traitements nécessaires
                    $this->view->blabla = 'HELLO WORLD";
                    //...
                    $this->view->slots = $this->view->render('planning/view-slots.phtml');
                    //...
                } else {
                    // S'il n'est pas valide, on est en erreur
                    $this->view->hasErrors = true;
                    $this->view->form = $this->view->render('planning/order-query.phtml');
                }
            }
    }
    Sachant que je rappelle que planning/order-query.phtml est un partial pour afficher le formulaire.
    Et que planning/view-slots.phtml est la vue pour afficher les nouvelles données :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    <div>
        <h1><?php eco $this->blabla; ?></h1>
        <p> Ici sont les nouvelles données issues de la requête Ajax </p>
    </div>
    Donc voilou la décomposition que j'ai mis en place. On se rend compte dans le principe que nos solutions se rappochent pas mal !

    Merci pour ta réponse !

  6. #6
    Membre régulier Avatar de eaglesnipe
    Homme Profil pro
    Ingénieur Etudes et Développement
    Inscrit en
    Janvier 2008
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur Etudes et Développement
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Janvier 2008
    Messages : 75
    Points : 76
    Points
    76
    Par défaut
    @GrandFather,

    En effet, cela pourrait être une possibilité. Tout mettre dans une même vue, avec au premier coup juste le premier formulaire d'affiché, et au fur et à mesure construire mes formulaires et les afficher toujours via la même vue (avec un contrôle genre est-ce que j'affiche celui-ci ?)

    Je me suis peut être finalement un peu compliqué la vie pour pas grand chose, mais il est vrai que j'aime bien avoir des fichiers "fonctionnels" et non pas tout le traitement dans une même vue. Pour le peu qu'on décide qui plus est (et ceci est fort probable) de gérer l'affichage des formulaires à la main (pour une raison x ou y) plutôt que le bon vieux echo $this->form, il est plus "lisible" d'avoir le code dans un partial bien séparé plutôt que dans une seule et unique vue noyée parmi des centaines et centaines de lignes de code. Mais ceci est un avis perso

    Quoi qu'il en soit merci pour ta remarque !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Requête ajax avec $.ajax()
    Par student_php dans le forum jQuery
    Réponses: 4
    Dernier message: 30/10/2011, 19h39
  2. Réponses: 2
    Dernier message: 05/07/2010, 11h23
  3. [Dojo] Requête AJAX avec paramètre avec DOJO
    Par Tavarez59 dans le forum Bibliothèques & Frameworks
    Réponses: 10
    Dernier message: 19/06/2009, 13h50
  4. [ClassLoader] Chargement dynamique d'une classe -> problème avec packages !
    Par ymerej dans le forum API standards et tierces
    Réponses: 9
    Dernier message: 31/05/2006, 21h37
  5. Réponses: 8
    Dernier message: 20/01/2006, 13h46

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo