Bonjour,
je me pose encore une question:
La vérification des données fournit par un formulaire html, dans une architecture MVC, doit être fait par le modèle ou par le contrôleur qui contrôle avant de fournir au model ?
Version imprimable
Bonjour,
je me pose encore une question:
La vérification des données fournit par un formulaire html, dans une architecture MVC, doit être fait par le modèle ou par le contrôleur qui contrôle avant de fournir au model ?
Bonjour,
Je pense que c'est au controller de vérifier la sanité des données.
Le modèle ne devrait pas faire ce genre de vérification.
S'il un objet du modèle existe c'est qu'il est sain, sinon il n'a aucune raison d'exister...
C'est au modèle de vérifier le bien fondé des données et pour cause : les données attendues dépendent précisément du modèle et sont traitées par celui-ci.
Selon MVC, le contrôleur ne fait que transmettre les données au modèle, rien d'autre en ce sens.
Et c'est justifiable :
En poursuivant dans ton raisonnement, si le modèle est utilisé par plusieurs contrôleurs, il faudrait recopier le code vérification des saisies à chaque fois.
La réutilisation est une bonne pratique orienté objet, pas le copier-coller.
Par ailleurs, le développeur tier qui aurait le malheur d'omettre le code en question risquerait de compromettre l'application toute entière...
Bye
le contrôleur ne s'occupe que d'une chose
la logique applicative
il utilise les services du modèle
transmet les données du modèle à la vue et de la vue au modèle
Il filtre au passage les données
mais ce n'est pas lui qui sais si le contenu des données est bon.
c'est le métier qui détiens cette info
en terme de filtre le contrôleur à juste en charge l'adaptation des données à la forme attendue soit par le modèle soit par la vue.
enfin le modèle est aussi utilisable par d'autres éléments que les contrôleurs
comme les webservices par exemple
si tu mets du métier dans le contrôleur il te faudra alors le remettre dans les services
A+JYT
Je me suis mal exprimé, mais quand je parlais de sanité des données je parlais de cette étape de filtrage. (validation de type, etc).Citation:
en terme de filtre le contrôleur à juste en charge l'adaptation des données à la forme attendue soit par le modèle soit par la vue.
Bien sur que le modèle ne doit accepter que des données valides...(validation d'un point de vue logique applicative).
le modèle se charge de vérifier que le numéro de code du client est conforme à la spécification d'un client
le contrôleur lui enlève des donnée issue de son formulaire les balise HTML ou le code SQL qu'un malotru chercherais à insérer
Le modèle vérifie que la date de rendez-vous demandé par le client est conforme au règles de prise de rendez-vous
le contrôleur lui récupère la chaine de caractère du champs date la dépouille de toutes les intrusion et en fait un élément du type attendu par le modèle. (init string date object etc.)
A+JYT
Ce n'est pas au contrôleur de filtrer les données en entrées, d'ailleurs le filtrage en entrée est inutile : la validation des saisies étant suffisante au niveau du modèle.
A quoi ça sert de filtrer un champ contenant des balises HTML sachant que celui-ci doit être valider par le modèle ? Ca n'a pas de sens...
...L'HTML est totalement inoffensif tant qu'il n'est pas analysé.
L'HTML devrait être échappé seulement si les données sont suceptibles d'être renvoyées au client ou si les données vont être analysées par l'application AVANT l'appel du modèle (ce cas peut se présenter si le contrôleur traite ou modifie des informations en entrée, ce qui n'est définitivement pas le rôle d'un contrôleur...(!)).
Pour les tentatives de requêtes SQL forgées, il suffit de faire des requêtes préparées.
La validation des données permet de s'assurer qu'une variable contient un certain type de données dans le format, les plages ou conditions spécifiées par le validateur.
L'échappement des données intervient après la validation de forme, à ce stade, on échappe tous les caractères dangereux.
L'échappement est également utilisé lorsque les données sont retournées au client.
Le filtrage des données fait suite à l'échappement, on formate les valeurs en vue d'un enregistrement ou d'une analyse interne (parse).
A mon avis, ce n'est pas une bonne approche que de vouloir à tout prix "corriger" les saisies utilisateur (sans parler de faire cela au niveau du contrôleur), après tout si un champ contient de l'HTML alors que vraissemblablement il ne doit pas en contenir, la seule chose à faire est de l'indiquer promptement au client et ne pas faire de son application "un redresseur de torts".
Les mauvaises saisies utilisateurs devraient être traitées comme des erreurs et non comme des exceptions.
P.S : Zend_Filter_Input.
parce que le modèle n'a pas à savoir si les données viennent d'un formulaires ou d'un webservice ou de tout autre chose
le métier lui à pour rôle de déterminer ce qui est Métier
en clair tu lui donne une date il vérifie que c'est une date valide pour sont travail et il s'en sert
il ne sait pas d'où vient cette date il ne sais si c'est une chaine de caractère qui est passer ici ou par là et qui est susceptible de contenir des parasite.
le métier est purement fonctionnel.
en clair il peut te dire que ce que tu lui donne est bien une date qu'elle correspond au règle de son métier
mais il ne peut savoir quels fitres devront être appliquer au champs du formulaire pour en faire une date vu qu'il ne connais pas le champs du formulaire.
A+JYT
Pour reprendre ce que dit Sekaijin :
Le modèle répond à une logique fonctionnelle.
Par exemple pour une prise de rendez vous, si une date est attendue, le controller doit vérifier que la donnée passée via le formulaire HTML est bien une date (par exemple du format JJ-MM-YYYY HH:MM), le modèle va lui avoir la charge de vérifier que cette date ne tombe pas un dimanche et que l'horaire soit entre 9h et 19h (par exemple).
Le modèle est chargé de faire en sorte que le domaine fonctionnelle soit respecté.
Le controller se charge de valider transformer les données pour qu'elle soit du "type" attendu par le modèle.
Il est important de séparer ces deux filtrages. Car le modèle doit être interopérable.
Admettons cette fois qu'au lieu de champs de saisie pour un rendez-vous, l'utilisateur doive fournir à l'application un fichier (type csv par exemple) qui contienne les rendez-vous.
Le modèle n'a que faire de HTML dans ce cas la. Le controlleur spécifique chargé de répondre à l'envoi du fichier, va filtrer les données du fichier pour en séparer les dates, les lieux, et les envoyer au modèle.
Donc en suivant votre raisonnement, si on me fournit un modèle je dois au préalable me renseigner profondément sur ses spécifications techniques pour ensuite créer un filtre au niveau du contrôleur, ceci dans l'espoir de formater mes données pour qu'elles soient traitables par le modèle en question...
A quel moment cela rend-il le modèle plus interpolaire ?
L'interpolarité se joue au niveau des modèles, vraissemblablement pas du contrôleur. Si d'autres développeurs utilisent vos modèles et qu'ils doivent les adapter à leur contexte, l'approche la plus commune (résolument orientée objet) consisterait à étendre le modèle en question pour qu'il accepte de nouvelles spécifications, ou mieux encore, permettre aux développeurs de créer leur propre modèle par rapport à une interface abstraite (classe abstraite ou interface).
Alternativement, si il s'agit de modification de forme, ça se passerait dans les vues.
Créer des filtres au "coup par coup" dans un contrôleur (je persiste dans l'idée que les filtres n'ont rien à faire là), ça relève du bidouillage, c'est la porte ouverte aux ennuis.
Aussi je ne comprends toujours pas cette propension à vouloir corriger les saisies utilisateur, et à la source !
Guardian_7 +1000 ;)
Si je te comprends
si ton modèle est utilisé par le contrôleur c'est à lui de savoir ce qu'il y derrière donc dans la vue. pour pouvoir fileter convenablement.si en même temps ton modèle sert à une interface JSON pour de l'ajax il doit savoir ce que fait le client web pour ne pas choper des truc non prévu. et si comme moi en plus ton modèle sert au passage à des services web c'est à lui encore de filtrer les éventuels ajouts ou bricolages dans l'appel SOAP
l'indépendance du modèle est plutôt remise en question il me semble
pour moi le modèle fournis une API fonctionnelle à celui qui l'utilise de la respecter.
Mayer allait plus loin dans cette approche selon lui un appel qui ne respecte pas l'API doit générer un Arrêt brutal de l'appli (core dump) car ce n'est pas une erreur de fonctionnement c'est un programme qui est FAUT
(ça s'appelle la programmation par contrat)
A+JYT
Je ne suis pas tout a fait d'accord avec toi sekaijin.
Si mon api ne me donne pas tout ce qu'il me faut, je la surcharge pour avoir les fonctionnalité désirées. C'est pour moi un principe fondamentale de l'objet.
Par exemple, si à chaque fois que tu as affaire à du soap du dois bidouiller avant d'utiliser l'api il vaut mieux que le bidouillage soit fait une bonne fois pour toute. C'est le principe de réutilisabilité.
Quand on parle d'indépendance du modèle, je pense que l'on veut dire que le modele doit être en gros autonome et ne pas dépendre de facteur extérieur.
Adapter un modele pour qu'il puisse gère du soap, du jason ou un formulaire basic ne remet pas en cause son independance. On devrait plutôt parler de fonctionnalité de la partie metier.
Je précise que cela ne remet pas en cause le principe que du site, car ce n'est pas parce qu'on étend une api qu'il ne faut pas respecter l'api elle-même.
sympa ce post,
je donnerais plutot raison à sekaijin...
si on compare à une ampoule et à une douille ( le contrôleur étant la douille et l'objet métier l'ampoule) on peut dire que le filtrage des données est une adéquation entre l'ampoule et la douille. Il faut évidemment que le contrôleur soit adapté à l'objet.
Il est certain que si on ne veut pas faire griller l'ampoule il faut aussi protéger l'ampoule des surcharges.
ça c'est la partie validation et c'est plutôt à l'objet métier de s'en charger.
conclusion : les validators sont des membres des objets métiers déclenchés par les filtres du contolleurs ;p
Bonjour,
Confronté à la même problématique, j'ai un peu réflechi sur le sujet.
Pour moi, c'est le modèle qui doit s'occuper de valider les données qui vont être insérées dans l'application. C'est dans sa définition même.
Par exemple, on définit une classe métier 'Reservation' avec un champ 'dateReservation'.
Avant d'insérer la donnée dans l'application, on doit s'assurer que premièrement l'utilisateur a bien saisi une date valide dans le formulaire (format AAAA-MM-JJ par exemple, et qui existe, pour pas se retrouver avec un 30 février ou un 29 février sur une année non bissextile), et deuxièmement que la date saisie respecte les règles de gestion définies dans le cahier des charges de l'application (pas exemple ne pas réserver une salle de réunion un dimanche!).
Si ces deux règles sont respectées, alors la saisie de l'utilisateur est validée et on peut continuer, et si au moins l'une d'elles ne l'est pas, on lance une erreur ou une exception qui empêche l'enregistrement des données et qui sera récupérée par le contrôleur pour être affichée dans la vue et informer l'utilisateur de ce qui ne va pas dans sa saisie.
On s'arrange ensuite pour factoriser le plus possible cela dans les classes métier, par exemple en définissant une classe mère 'BusinessClass', définissant une méthode de validation de données qui utilise un attribut redéfini dans chaque classe métier et qui contient toutes les règles pour chaque champ (Pour l'instant ce n'est qu'un idée, je ne suis pas passé à la réalisation, donc il y a peut être mieux).
Cela va donc dans le sens de Guardian_7, qui parlait de réutilisation. Si je suis l'approche de sekaijin, le contrôleur doit s'assurer que le format de données est valide, et le modèle ne vérifie pas. Si mon contrôleur est buggé et passe une date au format JJ/MM/AAAA au lieu de AAAA-MM-JJ, qu'est ce qui se passe?
Ce débat pointe une limite du zend framework, qui dans ce cas n'est pas assez structurant à mon sens. Toutefois, il me semble qu'un package Zend_Form doit être introduit dans le futur...
Qu'en pensez-vous?
il ne faut pas confondre la validation des données et le filtrage des données.
le filtrage vas nettoyer les champs des éléments parasites ou dangereux pour l'application. cela ne relève pas du métier
par exemple l'interface utilisateur fourni trois champs heure minute seconde
et le modèle manipule des donnée horaires
le filtrage va consister à supprimer de ses trois champs tout ce qui n'est pas une valeur numérique. construire une heure et la donner au modèle qui lui à la charge de valider la donnée. l'heure corresponds-t-elle bien aux règles métier.
le filtrage des données est du ressort du contrôleur car lui seul sait ce que gère la vue. il fournit une donnée acceptable par le modèle qui lui la valide.
la difficulté se situe au niveau de 'il fournit une donnée acceptable' dans un champs date par exemple on peut choisir qu'une chaîne de caractère est un date acceptable et ce sera au modèle de vérifier son format et de la valider.
ou choisir que seul une Zend_Date est une donnée acceptable. au quel cas le modèle se chargera de la valider et laissera le contrôleur se débrouiller pour lui fournir une date. c'est donc ce dernier qui vérifiera le format.
le filtrage va essentiellement consister à retirer les blanc inutiles, traduire les htmlentites, rejeter les injection sql, traduire les urlencodes,
et traduire les donnée du format user au format application. (tout comme c'est le contrôleur qui avec la vue traite l'internationalisation pour la présentation.)
la validation elle à en charge la vérification de de la conformité au règles métier.
la frontière n'est jamais évidente. mais une chose est sure imaginez que vous décidiez de fournir à votre utilisateur une interface en japonais. vous ne devez intervenir que sur la vue et sur le contrôleur. les règles métier ne change pas parce-que vous affichez et saisissez vos données en japonais. de même si vous choisissez d'autre langue ou d'autre présentation.
par exemple passer de la saisie d'une dans dans une champs texte à trois selectbox, ou le contraire. ce genre de changement ne doit avoir aucun impact sur le modèle.
en gros le filtrage réponds à la question "mes données sont elle utilisables dans mon application" alors que la validation répond à la question "mes données sont-elle conforme au règle de gestion de mon métier"
1 un deux 5 trois peuvent très bien être utilisables alors que le modèle manipule des entiers. et toutes ne seront pas acceptable si la règle métier dit que le nombre doit être < 3
A+JYT
Hello,
Je ne pense pas qu'on est à faire à une limitation du framework, il y'a tous les éléments permettant de créer une logique robuste pour le filtrage, la validation et l'échappement des données. En y réflechissant bien, ce n'est pas compliqué à implémenter (eratisator, je pense d'ailleurs que tu es sur la bonne voie !)
A mon avis, si les développeurs du ZF n'ont pas implémenté un tel concept, c'est pour que les modules conservent leur autonomie. C'est une bonne chose.
En ce qui concerne l'hypothétique Zend_Form, il est préférable de savoir faire sans, parceque ce n'est pas pour demain la veille...
Donc si je pige bien, on utilise les filtres dans le contrôleur pour enlever tous les éléments indésirables pouvant avoir été ajoutés dans la saisie (du genre les html entities, les espaces à trimmer, ...), et le modèle valide les données précedement filtrées suivant les règles qu'on établit...
Dans ce cas, je ne vois par contre pas bien l'intérêt de filtrer tous les caractères non numériques d'une saisie devant être numérique (par exemple), car si on ne filtre pas la validation échouera, et si on filtre, on risque de se retrouver avec des données n'ayant pas de sens du point de vue de l'application pour les forcer à passer la validation...
Donc on filtre en entrée tout ce qui peut être dangereux pour l'application, et ensuite on valide la donnée au niveau du modèle...
Je crois que je tiens le bon bout, plus qu'à implémenter tout ça pour être le plus efficace possible!
C'est précisément l'une des raisons pour laquelle je ne suis pas d'accord avec sekaijin.
Comme je l'ai déjà dit, si les données ne sont pas du type attendu, il ne faut pas chercher à les formater, à les rendre "présentables" pour le modèle, ce n'est pas une approche logique.
Ce genre de technique peut déboucher sur un "auto-goal" en matière de sécurité.
Le module Zend_Filter_Input pour l'exemple.Citation:
Envoyé par eratisator
Il fonctionne en trois phases (dans l'ordre) :On peut constater à travers ce mecanisme que le filtrage des données est facultatif. La plus part du temps il sera même totalement superflu...
- Il applique le(s) filtre(s) aux données.
- Il valide les données selon le(s) validateur(s).
- Il échappe les caractères spéciaux récursivement (par défaut).
La validation des données détermine si les données sont traitables par le modèle ou non. A ce niveau là, il y'a pas de danger significatif pour l'application à moins qu'il y ait une vulnérabilité au niveau de PHP (typiquement dans une fonction de la librairie interne, c'est déjà arrivé par le passé, mais c'est très rare) ou encore un contexte particulier (évaluation de code source dans un validateur par exemple).
Finalement Zend_Filter_Input échappe récursivement toutes les données. "L'échappeur" par défaut est le filtre HtmlEntities(), il convertit tous les caractères HTML non-ascii en entités.
Même si ces caractères ne sont pas échappés à ce niveau, ils ne compromettront pas l'application, ni la base de données durant leur insertion (au pire, il y aura des valeurs tronquées insérées dans une table). Cela pourra parcontre être un problème lorsque les données seront affichées ou analysées.
Les problèmes d'injections SQL ne sont pas traités au niveau du validateur, mais au niveau de l'ORM, avec des méthodes telles que quoteInto(), ou encore Zend_Db_Select, qui échappe nativement les variables dans une clause WHERE....
En conclusion, il suffit de valider les données avec les validateurs, et sécuriser les requêtes le cas échéant.
Pour te donner une idée... Tu pourrais intégrer Zend_Filter_Input dans une classe étendue de Zend_Db_Table_Abstract et redéfinir les méthodes insert() et update() de telle sorte qu'elles utilisent Zend_Filter_Input avant l'insertion ou la mise à jour de données. Si il y'a un problème de validation à ce niveau, il te suffirait de récupérer les messages d'erreurs de Zend_Filter_Input et de les placer dans une variable afin qu'ils soient retournés dans une vue.
Personnelement j'ai procédé de cette manière (bien que ce soit un peu plus poussé) et j'ai créé un View_Helper qui gère les messages d'erreurs (constantes) renvoyées par Zend_Filter_Input et les localise éventuellement dans plusieurs langues (ce qui n'est pas possible basiquement).
Bye
Cette discussion est très intéressante et je pense qu'il y a autant du vrai que du coté de sekaijin que de Guardian_7.
Notez que Zend_Form vient d'entrer en "review" :
http://framework.zend.com/wiki/display/ZFPROP/Zend_Form
J'y ai laissé un commentaire ("best practises to reuse validation rules". ) en relation avec cette discussion.
Si vous avez de bonnes idées je pense qu'il ne faut pas hésiter à commenter.
pour illustrer mon propos mon modèle utilise des dates
ces dates sont des objets
mon application présente un formulaire avec trois sélect boxCode:
1
2
3
4
5 ( year, mounth, day )
quoi qu'il arrive si mon contrôleur ne donne pas un objet construit avec les trois valeurs des selectbox mon modèle répondra invalide
je pourrais adapter mon modèle
mais alors mon modèle dépends de la vue
et si ma vue évolue je devrais encore changer mon modèle.
si c'est le contrôleur dont le rôle est d'orchestrer les échanges entre la vue et le modèle qui se charge de ce travail l'évolution de la vue implique une adaptation du contrôleur mais pas du modèle.
inversement mon modèle évolue et je n'utilise plus un objet à trois champs pour mes dates mais une chaîne. le contrôleur est adapté mais pas la vue.
lorsque j'internationalise mon application il me parait logique de formater les date issue du modèle dans un format compréhensible de l'utilisateur. et il est évident que ce n'est pas le modèle que le fait. c'est le contrôleur. le métier ne change pas parce que je suis passé en français espagnol ou japonais
je ne vois pas pourquoi il en serait autrement dans l'échange inverse c'est à dire entre la vue et le modèle. c'est le contrôleur qui récupère les données de la vue dans la langue de l'utilisateur c'est lui qui sait dans quelle langue travaille l'utilisateur et c'est lui qui sait quel type de donnée attend le modèle.
je ne comprends pas qu'on veuille reporter ce travail au modèle.
Je travaille dans une équipe et ce n'est presque jamais les même personnes qui s'occupe de cœur de métier, de la logique applicative, et de l'IHM
on défini donc une API au niveau du modèle et les contrôleurs mais aussi les webservices doivent tous s'y conformer sans ça THROW MODEL_EXCEPTION
pareil pour le modèle il doit respecter le contrat (API)
de même on définit les échange (l'API, le protocole) entre la vue et le contrôleur. et chaque équipe doit s'y conformer. si la vue ne se conforme pas
le contrôleur lève une exception, de même si le contrôleur ne donne pas à la vue ce qu'elle attends celle-ci plante.
et on peut mettre en place tous les mécanisme que l'on veut si tu appelle une fonction qui attend un entier avec un chaîne ça plante et c'est normal.
quant à mon exemple sur le filtrage des valeur numérique. en php ça parait pas très évident vu que le langage est faiblement typé.
mais avec un autre langage si ta fonction de validation attend un entier tu te fais jeter avant même d'avoir tenté de valider ta donnée et c'est bien au contrôleur de s'assurer que ce qu'il donne au modèle est SYNTAXIQUEMENT correct le modèle s'occupant lui de la validation SÉMANTIQUE.
Maintenant je comprends que lorsqu'on est seul ou peut nombreux, et que l'on maîtrise de bout en bout on prenne des facilités. la lecture d'un entier dans un champ relève de l'analyse syntaxique et la vérification que l'entier lu est conforme au métier de la sémantique.
séparer les deux améliore grandement la robustesse et l'evolutivité ainsi que la réutilisabilité. mais cela fait faire plus de travail au moment du développement.
et je comprends très bien qu'on décide de donner directement la chaîne de caractère à la fonction qui doit vérifier que le paramètre est bien compris entre 0 et 100, mais il faut être conscient que celle fonction du modèle implique une dépendance à la vue chose que le modèle MVC cherche à minimiser.
A+JYT
Le choix de la "facilité" c'est d'appliquer des principes de conception empiriques, voir arrivistes au detriment de processus éprouvés.
Lorsque je développe une application orientée objet, je commence par analyser le problème dans sa généralité (et dans la possible réutilisation des solutions), je ne pars pas d'une situation particulière ou d'un cas d'utilisation conret.
Dans la phase de conception, j'essaie d'appliquer des solutions éprouvées ou a priori académiques, et ensuite seulement, je me préoccupe des problèmes d'implémentation.
Apparement c'est la base de nos divergences sekaijin...
...Il s'agit simplement de respecter un motif de conception, dans l'intéret commun du développeur et du client... Ce n'est pas parceque c'est PHP et qu'il s'agit de développement Web, qu'il faut partir dans tous les sens.
Bref.
Démontre-moi clairement que tes solutions sont meilleurs, par rapport à ZF, son modèle MCV et ses modules de filtrage. Si possible sans t'écarter du sujet...
justement je ne pense pas que se soit partir dans tous les sens que de bien cibler ce qui relève du métier de ce qui relève de son usage.
pour moi le métier et un bloc bien définit avec une api claire qui ne dois avoir à être modifié parce qu'on l'utilise ici où là.
donc lorsque ma MOA me dit que la règle c'est celle là mon métier implémente la règle rien de plus.
et si ma MOA me dit que veut changer la présentation des données je ne veux pas avoir à toucher à mon modèle.
et si demain elle me dit que mon application doit d'interfacer avec une autre je ne veux pas avoir à toucher à mon métier.
J'applique donc des pattern logique et éprouvé
la vue présent
le contrôleur contrôle
et le modèle traite
Meyer à qui on doit de nombreux travaux sur la POO à surtout introduit un truc qu'on n'utilise pas assez qui s'appelle la programmation par contrat
en clair lorsque tu fait un objet une méthode un package tu définit une interface une API de fait de définit un contrat avec le développeur qui veut l'utiliser. s'il ne respecte pas le contrat il n'y a aucune raison de chercher à traiter sa demande. ces à lui de faire le nécessaire pour bien utiliser l'API.
lorsque je développe je considère que je passe un contra avec les développeurs des fonction et objet des librairie que j'utilise et c'est à moi programmeur de faire en sorte que je les utilises correctement.
et lorsque je fais appel à une fonction php je la prends comme elle est. je ne lui demande pas de s'adapter à tout les types et valeurs possible de tout et n'importe quoi.
lorsque j'appelle une fonction qui demande un entier je m'assure de lui donner un entier. et si elle veut une chaîne je lui donne une chaîne.
lorsque je veux ouvrir un fichier en écriture je m'assure que le paramètre que j'utilise est bien une chaîne de caractère.
puis je demande à l'API de me dire si oui ou non du point de vu de son métier de gestion de fichiers ma chaîne est valide pour ouvrir mon fichier. et enfin je demande au métier de faire le boulot c'est à dire d'ouvrir le fichier.
si je donne un tableau ou un entier à fopen je vais me prendre une exception et c'est normal c'est à mois de vérifier ça avant. une fois que je l'ai vérifié je peux alors demander au métier de me valider ma donnée is_writable
pour moi entre le contrôleur et le métier on est exactement dans ce cas.
le contrôleur s'assure que ce qu'il donne au métier est bien ce qu'il attend lui demande de valider sémantiquement la donnée et lui demande de la traiter.
c'est le schema que l'on trouve partout dans la programmation
à chaque fois que tu appelle une fonction que tu utilise un objet utilise un protocole.
je ne vois pourquoi j'irais inventer un truc à alors que cette façon de faire est éprouvée robuste évolutive et réutilisable.
A+JYT
Bonjour,
Je pense un peu comme sekaijin.
Il faut distinguer la validation/filtrage technique de la validation/filtrage fonctionnel-métier.
La première répond à des problèmatiques techniques, elle est à la charge du controleur, et est chargée de valider/filtrer les données pour qu'elles répondent au contrat que constitue l'API du modèle (typiquement par exemple transformer les chaines de caractères de type "jj-mm-aaa" en objet de type Date qui va contenir des champs jour; mois; année si le modèle attend une Date).
La deuxième valide les données pour répondre à la logique métier, les erreurs retournées par cette validation sont des erreures propres aux métiers ("Date invalide car il existe deja un rendez vous ce jour là").
Le modèlé ne devrait pas lever d'erreur du genre "La chaine de caractère saisie ne correspond pas à une date valide" si la date saisie par l'utilisateur est 37 juin 2007. Il s'agit là d'une validation technique.
L'apologie du filtrage, je pense qu'on en a fait le tour au moins 3 fois ;). La question c'est son application dans le Zend Framework.
J'attends toujours qu'on me démontre l'efficacité (l'utilité) évidante des filtres au niveau d'un contrôleur d'action.
Le reste relève visiblement du mono-dialogue...
La question, même si ici concerne le Zend Framework, est tout de même une question relative à la conception logicielle. Elle concerne particulièrement la responsabilité du filtrage/validation des données en provenance d'une vue dans le cadre d'une application MVC.Citation:
L'apologie du filtrage, je pense qu'on en a fait le tour au moins 3 fois . La question c'est son application dans le Zend Framework.
L'efficacité réside dans la robustesse de la conception : une indépendance du modèle par rapport à la vue.Citation:
J'attends toujours qu'on me démontre l'efficacité (l'utilité) évidante des filtres au niveau d'un contrôleur d'action.
Et pour répondre à la question initialement, à savoir : qui se charge du filtrage des données dans une application MVC ? Je dirai le modèle et le contrôleur, tout dépend si ce filtrage répond à une logique métier ou non.
:)
Si tu lis les précédents messages, tu devrais constater qu'on a effectivement causé conception, et qu'on a tourné en rond ;).
J'essaie simplement de recentrer le sujet sur des choses un peu plus constructives.
On est d'accord là-dessus.Citation:
Envoyé par Aurelpitiless
Je repète ma question, en quoi le fait d'introduire des filtres au niveau des contrôleurs d'action est utile, efficace, réutilisable en fin de compte ? :)Citation:
Envoyé par Aurelpitiless
Je précise : Je parle bien des contrôleurs d'action du Zend Framework.
ça ne change rien en terme de rapidité
de toute façon tu vas faire un test pour vérifier le type (le format) et un autre pour le métier
que tu mette ça dans une fonction ou deux fonction ça ne changera rien.
le seul truc c'est que si tu les sépare un rend ton modèle moins dépendant de ta vue et donc potentiellement plus réutilisable. de même ta vue étant moins dépendante du modèle elle est plus évolutive et plus robuste.
tu va y gagner aussi en terme de partage du travail.
et pour finir tu peux généraliser le contrôleur au moins en partie.
tu vas donc être plus efficace dans tes développements. mais ton code lui devra de toute façon faire les deux vérifications. ne sera pas plus rapide.
A+JYT
Je suis d'accord avec toi sur le fait qu'il n'y aura pas de différence significative au niveau du temps d'exécution. Ce n'est pas un facteur très important à ce niveau.
Plus réutilisable, je ne suis pas d'accord. En suivant ton raisonnement, il faudrait copier systématiquement les régles de filtrage dans chaque contrôleurs d'action (ça a déjé été dit précédement).
Généraliser tout ou partie du contrôleur pour des tâches de filtrage serait inaprorié...
Si le travail est réparti entre plusieurs développeurs, ils devront connaître les spécifications du modèle (les régles de validation Zend_Validate) ainsi que les régles de filtrage (Zend_Filter) figurant dans les contrôleurs et qui peuvent varier...
Je pense que séparer l'implémentation de ces deux modules n'est pas un signe de robustesse pour l'application.
Zend_Filter_Input a été créé dans le but de regrouper ces deux modules et donc ces deux operations. Ce n'est pas par hasard...
...Si une classe métier implémente Zend_Filter_Input, il suffirait d'étendre la classe en question pour en modifier ses régles de filtrage ou de validation. Ca me semble être l'approche orientée objet la plus rationnelle.
lorsque j'ai un crud à faire je crée un contrôleur qui dérive d'une classe crudAction comme la Zend_controller_action
je lui donne une référence à mon modèle et le nom des méthode d'enregistrement de recherche et de validation d données
je lui donne aussi pour chaque champs du formulaire le type de donnée et la façon don la vue me les donnes (une date peut être un entier, une chaîne ou plusieurs entier)
je n'écrit aucune ligne de code pour mon contrôleur
et pourtant il fonctionne il valide et filtre correctement les données et m'affiche correctement les messages d'erreurs
cela est possible parce que chacun s'occupe que de sa partie.
je n'écrit plus de procédure de filtrage je ne fais que déclarer celle dont j'ai besoin.
par contre mon métier lui je ne peux pas le généraliser la règle de mon métier lui est propre. par contre valider une donner quelque soit la règle c'est toujours la même chose et l'API pour le faire est toujours la même
je peux donc définir une interface et il suffit que le modèle implémente cette interface pour que je puisse généraliser mon contrôleur
Sans cette séparation claire impossible d'en arriver là
A+JYT
j'ai d'un côte ma vue
de l'autre mon modèle
le modèle implémente une interface de validation de données
mon contrôleur est toujours le même à des détail près
rechercher
afficher une liste
préparer un formulaire pour ajout
préparer un formulaire pour edition
afficher un formulaire
vérifier
enregistrer
j'ai donc une classe abstraite qui implémente tout ça
pour faire mon contrôleur je dérive cette classe et je lui dis comment assurer la liaison entre la vue et le modèle.
j'ai besoin pour ça de lui dire comment sont représenté les données des deux côté.
par exemple si mon modèle utilise un objet à trois champs pour représenter les dates et que ma vue elle utilise une chaîne de caractère
j'indique à mon contrôleur que pour le champs date il recevra de la vue une chaine q'il lui faudra donc utiliser le filtre DateString (éventuellement en fonction de la langue) que lorsque il aura une valeur acceptable il devra en faire une date sous forme d'objet pour le donner au modèle. qui la validera.
dans l'autre sens lorsque le modèle fournira une date elle seras transmise à la vue sous forme d'une chaîne formatée (en fonction de la langue)
je ne fais donc que du descriptif sur mes données
je ne m'occupe pas de ce qu'elle signifie ni de comment elle sont présenté
je ne m'occupe que d décrire ce qu'elle sont.
tout le reste est hérité de la classe abstraite.
ainsi lorsque je reçois des données du formulaire je les filtre en fonction de la description et j'obtiens des donnée compréhensible par le modèle (ou des code d'erreurs) il ne reste qu'à demander au modèle de valider les données.
pour passer à l'étape suivante.
c'est donc un comportement totalement générique que j'ai mis dans une classe abstraite. je n'ai donc rien à écrire pour la vérification de mon formulaire dans mon contrôleur.
il en va ainsi de toutes les actions du contrôleur vu que son seul job c'est de gérer les enchaînements d'action qui sont toujours les mêmes dans un crud
et de s'assurer l'échange de donnée entre le modèle et la vue. et pour ça il à juste besoin d'une description de cet échange
le champ vitesse du formulaire qui doit contenir un entier correspond au champs velocity du modèle qui est un float.
on voit bien qu'avec juste cette information on peut écrire un code générique qui assure l'échange. parsing du champs text du formulaire pour en extraire un entier et conversion en Float pour le donner au modèle. de même formatage du float du modèle pour donner une chaîne contenant un entier pour le donner à la vue.
donc mon crud est totalement générique pas de ligne de code à écrire pour qu'il fonctionne. juste du descriptif.
Voilà.
A+JYT
Merci pour ces précisions. Je commence enfin à comprendre ton raisonnement ;) - ça m'a l'air beaucoup plus valable expliqué de cette manière.
Je vais mettre tout ça à plat et comparer...
bye
Bonjour, j'ai parcouru ce post qui est vraiment intéressant.
J'aimerais avoir un petite précision sur les filtres et l'échappement des données dans la vue.
Sur la doc officielle du ZF ont peut lire :
Dans la vue, doit on échapper les champs retourner par un objet Zend_Filter_Input ?Citation:
37.3.1. Echapper la sortie
Une des tâches les plus importantes à effectuer dans un script de vue est de s'assurer que la sortie est correctement échappé ; de plus ceci permet d'éviter les attaques de type cross-site scripting (XSS). A moins que vous n'utilisiez une fonction, une méthode , ou une aide qui gère l'échappement, vous devriez toujours échapper les variables lors de l'affichage.
Dans mon formulaire si je rentre un "é" et que je le soumet à un filtre. lorsque j'utilise $this->escape($this->dataForm->nom) j'obtiens un "é" sans échapper j'ai bien le "é". Mais dans se cas est ce que mon formulaire est sécurisé ?
Bonjour,
Par défaut, lorsque tu récupères des données passées dans Zend_Filter_Input, elles sont échapées avec le filtre Zend_Filter_HtmlEntities (qui utilise la fonction interne htmlentities).
En pratique, il y a seulement certains caractères qui sont dangereux et qui doivent toujours êtres échappés, il sont listés dans la doc de la fonction interne htmlspecialchar(). Lorsque tu échappes tes données dans une vue (avec Zend_View::espace()), c'est cette fonction qui est appelée par défaut.
Par ailleurs, si tu utilises les View Helpers (FormInput, FormSelect, etc...) pour créer des éléments de formulaires, les valeurs utilisées seront également échapées avec le filtre spécifié par défaut dans Zend_View, attention donc à ne pas échapper deux fois les mêmes valeurs.
bye
Merci pour ta réponse, donc j'échappai 2 fois la même valeur...