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

Langage PHP Discussion :

[POO][MVC] où positionner les contrôles de saisie des formulaires


Sujet :

Langage PHP

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Inscrit en
    Mars 2006
    Messages
    70
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 70
    Par défaut [POO][MVC] où positionner les contrôles de saisie des formulaires
    Bonjour,

    J'ai un controller d'action, par exemple Action_user_validercreer.php qui doit contrôler techniquement et fonctionnellement la saisie avant de faire enregistrer le nouveau user.

    Pour gérer la persistance et la notion Objet, j'ai les classes suivantes :
    - une classe Class_User.
    - une classe Manager_User

    Manager_User, dont je me suis inspiré des cours PHP si je me souviens bien, permet d'accéder à la base de donnée, et donc à la table user correspondante.
    Class_User est l'objet User.

    Ma question, on y vient, est la suivante : où mettre le code de contrôle des saisies d'un formulaire de création d'un nouveau user ?

    Aujourd'hui, il est dans le Manager_User et la fonction controlerSaisie() renvoie une instance de Class_User nettoyée et créée à partir des variables $_POST[...]. Manager_User possède un attribut $_msg non vide si des erreurs sont détectée. Cet attribut est testé par l'Action pour savoir si on peut continuer ou renvoyer sur la page de saisie avec le message (je ne sais pas - encore - gérer les exceptions)


    Je trouve que mon Manager est trop gros, il comporte déjà toutes les fonctions d'insert, d'update... or les contrôles peuvent être nombreux, surtout pour des classes bien plus grosses qu'un simple user à 4 champs.

    Surtout, je trouve qu'il est pollué par les variables $_POST[...] renvoyées par le formulaire.

    C'est pourquoi je pense qu'il a trop de responsabilités.

    En même temps, mettre ces contrôles dans Class_User ne me semble pas plus pertinent, et pour la même raison.

    La solution est-elle de créer une classe Form_User pour gérer les contrôles sur les formulaires ? Cette classe renverrait l'objet Class_User propre à partir de la variable $_POST[].


    Sinon, qu'auriez-vous fait à ma place ?

    J'attends vos réponses avec impatience.

  2. #2
    Expert confirmé
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Par défaut
    Bonjour

    C'est logiquement le rôle des contrôleurs de contrôler Tes classes User et Manager, d'après ce que j'en ai compris ne font AUCUN contrôle, ce n'est pas leur rôle: elle ne font que les traitements métier et modèle nécessaires d'après ce que le contrôleur au dessus d'elles leur à donné. la validation c'est du domaine de la couche présentation, ça n'apparaît pas au niveau du modèle.

    Personnellement dans ce cas là, j'utilise des classes de validation distinctes capable de filtrer les données reçues de $_REQUEST et de répondre true ou false à la méthode validate, ce sont ces classes qui ont la connaissance et la responsabilité de la validation des données destinées au modèle.

    C'est jamais très bon de donner trop de responsabilité à une classe, on finit toujours par s'en mordre les doigts

    Edit: Dans mon cas, je préfère donner les méthodes CRUD à mes objets modèle et laisser au manager le soin de proposer des méthodes de traitement par lot, de listing avec pagination et ce genre de chose.

  3. #3
    Membre confirmé
    Inscrit en
    Mars 2006
    Messages
    70
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 70
    Par défaut
    Merci Benjamin pour cette réponse rapide.

    En réfléchissant rapidement à l'implémentation, je voudrais avoir une précision. Tu dis que la méthode de validation retourne un booléen.

    Que reçoit ta méthode en paramètre ? où et comment sont structurées les données validées ?
    Ces dernières sont-elles un attribut d'une classe ? laquelle ? car comment les récupérer ensuite pour instancier mon objet que je veux afficher ou insérer en base ?

  4. #4
    Expert confirmé
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Par défaut
    Il y a un moment j'avais posté sur le forum une astuce pour valider les données d'un 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
     
    <?php
    header('Content-type: text');
     
    $parameters = array('name' => 'bob', 'surname' => 'robert', 'mail' => 'bob@yopmail.com');
    $default = array("name" => null, "surname" => null,  "age" => 0, "mail" => "");
     
    $inputs = array_merge($default, array_intersect_key($parameters, $default));
    if (in_array(null, $inputs, true))
    {
    	echo "Missing parameters";
    }
     
    var_dump($inputs);
    Avec cette méthode toute simple, tu peux valider un formulaire en utilisant éventuellement des valeurs par défaut.

    Tu pourrais utiliser une classe qui ressemblerait à ça:
    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    <?php
     
    /**
     * @class DataValidationHelper
     * ----------------------------------------------------------------------------------------------------------------------- *
     * Intended to manage data validation
     * ----------------------------------------------------------------------------------------------------------------------- *
     * @author Delespierre
     * @package Data
     */
    class DataValidationHelper
    {
    	protected $_default_parameters = array();
    	protected $_invalid_entries    = array();
     
    	/**
    	 * Default constructor, takes the default parameters list
    	 * and their values as parameter
    	 * @param array $default_parameters
    	 */
    	public function __construct ($default_parameters)
    	{
    		$this->setDefaultParameters($default_parameters);
    	}
     
    	/**
    	 * Default parameters setter
    	 * Will return false in case of error
    	 * @param array $p
    	 * @return DataValidationHelper
    	 */
    	public function setDefaultParameters ($p)
    	{
    		if (is_array($p) && !empty($p))
    		{
    			$this->_default_parameters = $p;
    			return $this;
    		}
    		return false;
    	}
     
    	public function getInvalidEntries ()
    	{
    	    return $this->_invalid_entries;
    	}
     
    	/**
    	 *
    	 * Enter description here ...
    	 * @param unknown_type $data
    	 */
    	public function validate ($data)
    	{
    	    $inputs = array_merge($this->_default_parameters, array_intersect_key($data, $this->_default_parameters));
     
    	    // If a mandatory parameter is missing, validation success
    	    if (!in_array(null, $inputs, true)) return false;
     
    	    $this->_invalid_entries = array_keys(array_intersect($inputs, array(null)));
    	    return false;
    	}
    }
     
     
    // ----- //
    // TESTS //
    // ----- //
     
    header('Content-type: text');
     
    // use case 1
    $parameters_1 = array(
    	'nom'    => 'leponge',
    	'prenom' => 'bob',
    	'age'    => '13');
     
    // use case 2
    $parameters_2 = array(
        'nom'    => null,
        'prenom' => 'salade',
        'mail'   => 'test@test.test');
     
    // Paramètres de validation
    $default = array(
    	'nom'    => null, // Mandatory
        'prenom' => null, // Mandatory
        'age'    => 0,
        'mail'   => '');
     
    $validator = new DataValidationHelper($default);
     
    echo "Use case 1: ";
    var_dump($validator->validate($parameters_1));
     
    echo "Use case 2: ";
    var_dump($validator->validate($parameters_2), $validator->getInvalidEntries());
    Bon c'est une classe faite en 2 minutes mais ça donne une petite idée de ce à quoi pourrait ressembler tes objets ou classes de validation. A toi d'en faire une classe abstraite ou un singleton si tu préfère sous cette forme.

  5. #5
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Juillet 2008
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Calvados (Basse Normandie)

    Informations forums :
    Inscription : Juillet 2008
    Messages : 36
    Par défaut
    La solution de Benjamin est pas mal et fonctionne bien.

    Néanmoins, j'aurais tendance à faire les choses comme celà (le code n'est probablement pas complet, pas testé, c'est du vite fait pour donner une idée):

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    <?php
    ////////////////////////////////// FORMULAIRES ///////////////////////////////////
    interface IForm{
    	public function getFields();
    	public function setFields($_fields);
    	public function addField(IField $_field);
    	public function save();
    	public function update();
    	public function validate();
    }
     
     
    //On implémente IFORM
    abstract class Form implements IForm{
     
    	protected $fields;
     
     
    	/*** Getters & Setters ***/
    	public function getFields(){
    		return $this->fields;
    	}	
     
    	public function setFields($_fields){
    		$this->fields = $_fields
    	}
     
    	/*** Ajout d'un champ au formulaire ***/
    	public function addField(IField $_field){
    		$this->fields[$_field->getName] = $_field;
    	}
     
     
    	/*** Méthodes d'enregistrement -> à surcharger selon les cas ***/
    	public function save(){
    		//TODO
    	}
     
    	public function update(){
    		//TODO
    	}
     
    	/*** Validation des données ***/
    	//Retourne un tableau d'erreurs
    	//Le tableau est vide si pas d'erreur, sinon les lignes sont de la forme : "nom_du_champ" => "message_erreur"
    	public function validate(){
     
    		$errors = array();
     
    		foreach( $this->fields as $identifiant => $field ){
    			if( !$field->isValid() )
    				$errors[$identifiant] = $field->getValidator()->getMessage();
    		}
     
    		return $errors;
     
    	}
     
    }
     
    //Une implémentation concrète de IForm, qui dérive de Form
    class FormUser extends Form{
    //Par héritage, ce formulaire est validable
    	protected $user;
     
    	public function __construct(){
    		//le code à exécuter à la construction
    	}
     
    	public function getUser(){
    		return $this->user;
    	}
     
    	public function setUser( User $_user ){
    		$this->user = $_user
    	}
     
    }
     
     
    ////////////////////////////////// CHAMPS ///////////////////////////////////
    interface IField{
    	public function getMessage();
    	public function getName();
    	public function getValue();
    	public function getValidator();
    	public function setMessage( $_message );
    	public function setName( $_name );
    	public function setValue( $_value );
    	public function setValidator( IValidator $_validator );
    	public function isValid();
    }
     
    //Implémentation abstraite de IField -> à dériver selon le type de champ à utiliser
    abstract class FormField implements IField{
     
    	protected $message; // le label du champs
    	protected $name; //Le nom du champs
    	protected $value; //la valeur du champ
    	protected $validator; //l'objet qui valdie ce champ
     
     
    	/*** Getters & Setters ***/
    	public function getMessage(){ return $this->message; }
    	public function getName(){ return $this->name; }
    	public function getValue(){ return $this->value; }
    	public function getValidator(){ return $this->validator; }
     
    	public function setMessage( $_message ){ $this->message = $_message; }
    	public function setName( $_name ){ $this->name = $_name; }
    	public function setValue( $_value ){ $this->value = $_value; }
    	public function setValidator( IFieldValidator $_validator ){ $this->validator = $_validator; }
     
    	/*** Validation de données
    		Renvoie true si la valeur du champs est valide
    		Sinon false
    	***/
    	public function isValid(){
    		$this->validator->setField($this);
    		return $this->validator->isValid();
    	}
     
     
    }
     
     
    ////////////////////////////////// VALIDATEURS ///////////////////////////////////
     
    interface IValidator{
         public function isValid();
         public function getMessage();
    }
     
    interface IFieldValidator extends IValidator{
    	public function getField();
    	public function setField( IField $_field );
    }
     
    //Implémentation abstraite de IValidator -> à dériver en validators plus précis
    abstract class FieldValidator implements IFieldValidator{
     
    	protected $field;
    	protected $message; //Le message d'erreur en cas de non-validation -> peut être affecté dans le constructeur des dérivées
     
    	/*** Getters & Setters ***/
    	public function getField() { return $this->field; }
    	public function setField( IField $_field ){ $this->field = $_field; }
    	public function getMessage(){ return $this->message; } 
     
    	//A implementer dans les dérivées pour faire la vérification de validité du champ
    	abstract public function isValid();
     
    }
     
     
    ?>
    A l'erreur de syntaxe occasionnelle près, ça me semble plutôt générique et chaque classe ne fait que ce qu'elle a à faire.

    Quand on passe des objets en paramètres, on prend garde à tester que ce sont bien des implémentations d'interfaces.

    Aucune instanciation dans les classes, on injecte les dépendances, on fait les instanciation au niveau du contrôleur (non représenté ici).

    Dans l'idéal, on délègue les opérations de sauvegardes à un "Saver". Une méthode qui mappe les champs de form et les propriétés de l'objet User devra aussi être ajoutée...

    Amusez vous bien.

  6. #6
    Membre confirmé
    Inscrit en
    Mars 2006
    Messages
    70
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 70
    Par défaut
    jonoz, je suis très impressionné !

    Pour ce qui est de ton code, je vais le regarder en détail car il me parait très intéressant. Je ne suis pas familier avec la programmation objet et je peine parfois à concevoir mon application. Par exemple, je n'ai créé aucune interface alors que ça parait très utile (je n'ai pas dit obligatoire). Ton exemple sera donc pour moi très enrichissant.
    Reste à comprendre comment greffer cette méthode sur mon architecture.

    Je reviens vers vous si besoin et pour mettre Résolu lorsque je n'aurai plus de question.

    Merci

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

Discussions similaires

  1. Intégrer des calendriers pour les champs de saisie des dates
    Par xaviermfx dans le forum Développement Web en Java
    Réponses: 4
    Dernier message: 25/07/2012, 00h21
  2. [AC-2007] les liste avec dans des formulaires access
    Par zibi7 dans le forum VBA Access
    Réponses: 6
    Dernier message: 04/08/2009, 16h05
  3. [AC-2003] positionner les focus en fonction des événements ?
    Par lil404 dans le forum IHM
    Réponses: 10
    Dernier message: 21/04/2009, 16h44
  4. Contrôle de saisi des textbox d'un gridview
    Par getz85 dans le forum ASP.NET
    Réponses: 2
    Dernier message: 18/02/2008, 10h40
  5. [debutant] contrôle de saisie et formulaire
    Par oceane751 dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 27/11/2005, 22h29

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