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

  1. #1
    Membre du Club
    Inscrit en
    Mars 2006
    Messages
    70
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 70
    Points : 53
    Points
    53
    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 éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    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
    Points : 7 762
    Points
    7 762
    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 du Club
    Inscrit en
    Mars 2006
    Messages
    70
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 70
    Points : 53
    Points
    53
    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 éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    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
    Points : 7 762
    Points
    7 762
    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 régulier
    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
    Points : 99
    Points
    99
    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 du Club
    Inscrit en
    Mars 2006
    Messages
    70
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 70
    Points : 53
    Points
    53
    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

  7. #7
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    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
    Points : 7 762
    Points
    7 762
    Par défaut
    Je ne suis pas familier avec la programmation objet et je peine parfois à concevoir mon application
    Les design patterns d'architecture logicielle peuvent t'aider dans la résolution de problèmes courant. Jette un oeil par là, c'est jamais perdu:http://martinfowler.com/eaaCatalog/

    je n'ai créé aucune interface alors que ça parait très utile (je n'ai pas dit obligatoire)
    Les interfaces ne font pas que des heureux, en effet. Beaucoup préfèrent largement utiliser la composition plutôt que l'interface.

  8. #8
    Membre du Club
    Inscrit en
    Mars 2006
    Messages
    70
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 70
    Points : 53
    Points
    53
    Par défaut
    Benjamin, oui, j'ai lu plein de trucs sur les design pattern sur Internet, mais je n'ai pas encore compris comment m'en dépatouiller avec certains d'entre eux.
    Merci pour le lien, il a l'air intéressant. Je vais essayer de m'y plonger dès que j'en aurai le temps car pour l'instant, l'urgence est de livrer mon appli même si elle ne respecte pas les standards.

    A bientôt

  9. #9
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    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
    Points : 7 762
    Points
    7 762
    Par défaut
    Attention hein, j'ai jamais parlé de standards. Comme son nom l'indique, un pattern est un patron de conception, rien ne t'empêche de modifier son comportement ou de créer une conception à ta sauce, ce ne sera pas faux pour autant.
    Ce sont simplement des guides qui t'évitent de te casser la tête à réinventer la roue à chaque fois.

  10. #10
    Membre du Club
    Inscrit en
    Mars 2006
    Messages
    70
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 70
    Points : 53
    Points
    53
    Par défaut
    Bon,

    J'ai essayé de comprendre le code de jonoz car ça me semble un très bon cas pour m'améliorer... mais je suis à la ramasse.

    J'ai essayé de partir d'un cas concret et très simple. Voici ce que je veux faire : je veux tester un formulaire qui renverrait 1 variable : $_POST['id_user'] (faut commencer léger !).
    La variable doit être un Integer, c'est tout, testé avec filter_var par exemple.

    J'ai commencé à créer la classe User (puisqu'on doit gérer un objet User dans FormUser) ainsi :
    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
    class User
    {
      protected $_idUser;
     
      public function getIdUser() {
        return $this->_idUser;
      }
     
      public function setIdUser($_idUser) {
        $this->_idUser = $_idUser;
      }
     
    }
    Puis je me suis dit qu'il fallait au contraire créer un valideur pour les entiers :
    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
    <?php
    class FieldValidator_Integer extends FieldValidator
    {
      public function isValid()
      {
        if( filter_var( $this->getField()->getValue, FILTER_VALIDATE_INT ) )
        {
          $this->_message = '';
        }
        else
        {
          $this->_message = 'ce champ n\'est pas un entier';
        }
      }
    }
    Oui mais au milieu il me manque les champs ! Allons pour créer un champ !

    Je me suis lancé dans la création de la classe FormField_IdUser et c'est là que le bat blesse car je veux lui dire que le valideur est FieldValidator_Integer.

    J'ai voulu le faire dans le constructeur mais je ne sais pas comment faire. Je n'ai pas d'instance de FieldValidator_Integer !!

    Dois-je créer une telle instance ? où ?
    Je suis perdu...
    Bref, tout cela est bien beau, mais quand je veux aller à la pratique, ça patine sévère !!

    Sauriez-vous me donner des pistes ?

  11. #11
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    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
    Points : 7 762
    Points
    7 762
    Par défaut
    Allez, te décourage pas, je vais essayer en partant de l'exemple de Jonoz de te faire un truc pas à pas

    @jonoz, je vais sûrement avoir envie de transformer un peu ton code, ne m'en veut pas.

    Remarque si ça aboutit, ce serait un super sujet pour un article.
    Je vais détailler les étapes au fur et à mesure que je les réalise, comme ça ça te donnera également des notions d'objet en PHP.
    Je tiens à préciser que j'utiliserai PHP 5.3 couplé avec PDO et que rien au monde ne me fera changer d'avis (sauf le projet Qercus peut être mais je m'égare...)


    1 - Créer l'arborescence du projet

    On va utiliser l'arborescence des projets de Zend, elle est pratique et simple à comprendre:

    (ne tiens pas compte du fichier à la racine du projet, c'est une ancienne version)

    On va créer un bootstraper assez simple pour commencer avec juste un autoloader: fichier src/application/bootstrap.php
    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
     
    <?php
     
    // -----------------------------------------------------------------------------------------------------------------------------------------
    // Init constants
    // -----------------------------------------------------------------------------------------------------------------------------------------
     
    // Application paths
    define("APPLICATION_PATH", './application/');
    define("CONFIG_PATH",      './application/config/');
    define("CONTROLLERS_PATH", './application/controllers/');
    define("MODELS_PATH",      './appliication/models/');
    define("VIEWS_PATH",       './application/views/');
     
    // Library paths
    define("LIBRARY_PATH",     './library/');
     
    // Public paths
    define("PUBLIC_PATH",      './public/');
    define("IMAGES_PATH",      './public/');
     
     
    // -----------------------------------------------------------------------------------------------------------------------------------------
    // Autoloader
    // -----------------------------------------------------------------------------------------------------------------------------------------
     
    $autoload = function ($classname) { $path = MODELS_PATH . str_replace('\\', '/', $classname) . '.class.php'; };
    if (!spl_autoload_register($autoload)) die("Cannot register autoloader");
    là suite demain là j'ai pas le temps.
    Images attachées Images attachées  

  12. #12
    Membre du Club
    Inscrit en
    Mars 2006
    Messages
    70
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 70
    Points : 53
    Points
    53
    Par défaut
    Benjamin,

    Je vais te fournir ici mon arborescence projet avec quelques explications, on y gagnera du temps tous les deux, sauf si tu veux écrire un vrai tuto !

    Arborescence (simplifié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
    /* (pour éviter la coloration syntaxique ici !)
    racine/
        .htaccess
        config.php
        config_env.php
        index.php
        css/
        img/
        js/
        offline/
            .htaccess
            Fonctions.php
            MyPDO.php
            Request.php
            Response.php
            View.php
            /Action
                Action_Template.php
                /Accueil
                    Action_accueil.php
                    Action_accueil_index.php
                /Compte
                    Action_compte.php
                    Action_compte_connexion.php
                    Action_compte_deconnexion.php
                    Action_compte_modifier.php
                    Action_compte_validercreer.php
                    Action_compte_voir.php
                    ...
                /User
                    Action_user.php
                    Action_user_annulercreer.php
                    Action_user_annulermodifier.php
                    Action_user_confirmersupprimer.php
                    Action_user_creer.php
                    Action_user_index.php
                    Action_user_modifier.php
                    Action_user_modifiermdp.php
                    Action_user_validercreer.php
                    Action_user_validermodifier.php
                    Action_user_validermodifiermdp.php
                    Action_user_voir.php
                ... d'autres actions pour d'autres modules métiers
            /Class
                Class_User.php
                ....
            /Controller
                Controller_Action
                Controller_Front
            /lib (librairie pour PHPExcel, PEAR...)
            /Manager
                Manager_User.php
            /views
                accueil/
                    index.php
                compte/
                    connexion.php
                    creermodifier.php
                    recreermdp.php
                    voir.php
                user/
                    creermodifier.php
                    index.php
                    voir.php
    */
    A partir de là, tout est piloté à partir de index.php (je ne t'apprends rien) et par les deux fichier Controller_Front.php puis Controller_Action.php.
    J'ai ici un soucis car je fais un dans ma class Controller_Action, et j'ai bien peur que ça ne soit pas très propre. Mais peu importe ici, je règlerai ce problème plus tard.

    A partir de l'url ou d'une variable $_POST, on détermine le module (ic accueil, compte ou user) et l'action (creer, index, recreermdp... index est par défaut). C'est alors le fichier Action_{module}_{action}.php qui pilote les choses à faire.

    Notre étude de cas concerne la validation des formulaires, j'aurai donc par exemple :
    Action_user_validercreer
    et
    Action_user_validermodifier
    qui doivent faire la même chose à ceci près que l'un doit avoir un idUser renseigné et faire un update alors que le premier n'a pas d'idUser et doit faire un insert en base.

    Un mot sur mes autres classes :

    Class_User est une classe métier pure : des attributs qui peuvent être des objets ou des SplObjectStorage.

    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
    <?php
    class Class_User
    {
    	protected $_idUser;
    	protected $_loginUser;
    	protected $_mdpUser;
     
    	public function getIdUser() {
    		return $this->_idUser;
    	}
     
    	public function getLoginUser() {
    		return $this->_loginUser;
    	}
     
    	public function getMdpUser() {
    		return $this->_mdpUser;
    	}
    	public function setIdUser($idUser) {
    		$this->_idUser = $idUser;
    	}
     
    	public function setLoginUser($loginUser) {
    		$this->_loginUser = $loginUser;
    	}
     
    	public function setMdpUser($mdpUser) {
    		$this->_mdpUser = $mdpUser;
    	}
     
    	function __construct(Array $user = NULL) {
    		$this->hydrate($user);
    	}
     
    	public function hydrate(Array $user = NULL) {
    		if(!isset($user['id_user']) or '' == $user['id_user']) {
    			$this->_idUser = '';
    		} else {
    			$this->_idUser = $user['id_user'];
    		}
     
    		if(!isset($user['mdp_user']) or '' == $user['mdp_user']) {
    			$this->_mdpUser = '';
    		} else {
    			$this->_mdpUser = $user['mdp_user'];
    		}
     
    		if(!isset($user['login_user']) or '' == $user['login_user']) {
    			$this->_loginUser = '';
    		} else {
    			$this->_loginUser = $user['login_user'];
    		}
    	}
    }
    Manager_User qui est la classe qui fait l'interface entre l'objet User et la base de donnée (+ d'autres objets et d'autres tables s'il y a composition ou lien fort - jointure).
    Le code de cette classe est-il vraiment nécessaire ici ?

    Action_user_validercreer :
    dérive de Action_user qui a une méthode et des variables communes préparées dans le constructeur __construct.
    Action_user étend elle même Action_Template.

    Les variables récupérées sont :
    $_POST['id_user'] (vide ici puisqu'on veut créer un nouveau user)
    $_POST['login_user']
    $_POST['mdp_user'] (qui sera hashé bien entendu)
    Si les variables sont ok, on crée instancie Class_User avec les variables et on insère via Manager_User.
    Si les variables ne sont pas bonnes, on renvoie vers le formulaire avec les messages d'erreur qui expliquent ce qui ne va pas.

    Voilà le cadre !!

    A partir de là, comment je me dépatouille avec les classes de ce cher jonoz ?

    D'avance merci (et on peut faire par étapes, ça ne me dérange pas du tout).

  13. #13
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    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
    Points : 7 762
    Points
    7 762
    Par défaut
    Nan je vais compléter. Mais là présentement, je suis au boulot donc ton tuto je peux le faire que le soir quand j'ai 2 minutes.

  14. #14
    Membre régulier
    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
    Points : 99
    Points
    99
    Par défaut
    Hello,

    Pas pu revenir suivre le thread en début de semaine, désolé.

    Si besoin je peux aussi donner des précisions sur MVC et comment je l'implémentais quand je faisais encore ça à la main.

    Sinon Benjamin, c'est super si tu modifies/améliores mon code, qui a je le répète pour vocation non pas de fonctionner tel quel mais de donner un ordre d'idée de comment on peut faire ce genre de choses de façon relativement propre et générique.

    Pour les interfaces, ça permet un couplage relativement lâche et une certaine généricité.

    La composition est dangereuse dans beaucoup de cas. Elle a pour gros intérêt de permettre à une classe de contrôler elle même le cycle de vie de ses composants mais du coup induit un fonctionnement moins flexible.

    Dans mon exemple, on part du principe que les dépendances sont injectées au niveau du contrôleur, ce qui est une façon standard de faire. Si on fait de la composition, les dépendances sont instanciées au sein de la classe (en général à la construction). Utiliser la composition ou l'aggrégation est une bonne idée quand on est sûr qu'un et un seul type sera TOUJOURS utilisé pour une variable donnée ou quand les entités métier représentées ont un cycle de vie liés dans la réalité.

    Ex d'association pertinente :
    -> une instance de maison et une instance de mur

    Ex d'association non-pertinente :
    -> une instance de maison et une instance de brique

    Pour les méthodes de persistance d'un objet métier, trois écoles :
    -> l'objet se connaît et sait s'enregistrer, se supprimer, s'updater.
    -> l'objet se voit injecter un objet "technique", c'est dans les grandes lignes le pattern decorator.
    -> l'objet est injecté à un autre objet "technique" qui effectue ces opérations pour lui (pattern delegation).

    Les méthodes 1 & 3 sont les plus courantes. Je préfère personnellement la 3.


    Normalement, pour faire un insert ou un update, on appelle une méthode save() qui fait:
    -> si l'id de l'objet est à -1 : insert
    -> si l'id de l'objet est différent de -1: update

    Dans l'idéal, le code sera du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    public function save( MonTypeObjet $monObjet ){
      if( $monObject->getId() == -1 )
         return $this->create($monObjet);
      else
         return $this->update( $monObjet );
    }
    Les méthodes create() et update() renvoient un flag qui spécifie que l'opération s'est bien passé.

    Du coup, on peut par exemple fixer de base l'id à -1 à la construction.
    Dans l'idéal, on utilisera une Factory qui instanciera un objet vide, d'id -1.

    Si on le fait à la construction, on ne fera pas un
    mais plutôt :
    Ce qui permettra de rendre le traitement plus sur en s'assurant au niveau de setId() que le paramètre est soit -1 soit un entier positif.

    Sur l'utilisation des _ dans le nommage des variables, c'est une convention personnelle (héritée de ma pratique de Java en ce qui me concerne). Je préfixe par _ toute variable qui est un paramètre de méthode pour lever d'éventuelles ambiguités. Je le faisais au départ seulement quand la classe avait un attribut de même nom, et j'ai progressivement étendu cette habitude à tous les paramètres de méthodes.

    Sinon, dans le code que j'ai donné en exemple, en fait je remplacerais l'appel à getValidator->getMessage() , en rajoutant une méthode à Field qui renvoie un message d'erreur, ça permettrait justement de renvoyer un message d'erreur autre qu'une erreur de validation (pourquoi je voudrais faire celà ? pour pouvoir gérer - par exemple via des exceptions - les erreurs techniques éventuelles).

  15. #15
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    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
    Points : 7 762
    Points
    7 762
    Par défaut
    Je passe juste confirmer que je vous ai pas oublié, je travaille sur la question, dès que j'ai un peu de temps je vous fait un topo sur le forum...

  16. #16
    Membre du Club
    Inscrit en
    Mars 2006
    Messages
    70
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 70
    Points : 53
    Points
    53
    Par défaut
    Quant à moi, j'ai compris comment utiliser les classes de jonoz.
    Je me suis fait un exemple, et les tests PHPUnit sont OK.
    Il m'a fallu un peu de temps, car comme je le disais, créer des interfaces et les utiliser n'est pas naturel pour moi.


    Maintenant, si j'ai bien compris, j'instancie mes objets dans mon controller :

    Ça veut dire que dans mon controller, avant de faire le $formulaire->validate(), il faut que j'instancie et crée tous mes objets (
    - les valideurs des champs,
    - les champs,
    - l'affectation des valideurs aux champs,
    - le formulaire,
    - l'affectation des champs au formulaire,
    - et enfin je peux lancer la validation
    ), c'est ça ?



    J'ai une autre interrogation autour de la validation :

    Dans mon esprit, j'ai une validation technique du champ : est-il bien un entier ? est-il bien un email ?
    Mais j'ai aussi une validation fonctionnelle ! Par exemple, est-ce que tel champ prend bien les valeurs 1 ou 2, seules autorisées, est-ce que les deux champs "mot de passe" (mot de passe + confirmation) sont identiques ?

    Où fait-on cette validation ?

    J'aurai tendance à dire qu'on a une première méthode estValideTechiquement() qui vérifie les champs du point de vue technique.
    Et une deuxième méthode estValideFonctionnellement() qui fait la validation fonctionnelle.
    Ensuite, mon contrôleur gère les deux appels l'un après l'autre avec les contrôles qui vont bien.
    Êtes-vous d'accord ?



    Autre interrogation sur les bonnes pratiques :

    Jusqu'à présent, je faisais une validation avec nettoyage des données. Dans les méthodes proposées, je ne vois pas de nettoyage (que le problème soit technique ou fonctionnel - je ne veux pas envoyer à l'insertion une valeur en dehors des valeurs possibles).
    Comment on s'y prend selon vous ? Où récupère-t-on dans les classes proposées les valeurs nettoyées ? Dans le contrôleur à l'analyse des messages de retour ?


    D'avance merci pour tous vos retours !

  17. #17
    Membre régulier
    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
    Points : 99
    Points
    99
    Par défaut
    Citation Envoyé par basket Voir le message
    Quant à moi, j'ai compris comment utiliser les classes de jonoz.
    Je me suis fait un exemple, et les tests PHPUnit sont OK.
    Il m'a fallu un peu de temps, car comme je le disais, créer des interfaces et les utiliser n'est pas naturel pour moi.


    Maintenant, si j'ai bien compris, j'instancie mes objets dans mon controller :

    Ça veut dire que dans mon controller, avant de faire le $formulaire->validate(), il faut que j'instancie et crée tous mes objets (
    - les valideurs des champs,
    - les champs,
    - l'affectation des valideurs aux champs,
    - le formulaire,
    - l'affectation des champs au formulaire,
    - et enfin je peux lancer la validation
    ), c'est ça ?



    J'ai une autre interrogation autour de la validation :

    Dans mon esprit, j'ai une validation technique du champ : est-il bien un entier ? est-il bien un email ?
    Mais j'ai aussi une validation fonctionnelle ! Par exemple, est-ce que tel champ prend bien les valeurs 1 ou 2, seules autorisées, est-ce que les deux champs "mot de passe" (mot de passe + confirmation) sont identiques ?

    Où fait-on cette validation ?

    J'aurai tendance à dire qu'on a une première méthode estValideTechiquement() qui vérifie les champs du point de vue technique.
    Et une deuxième méthode estValideFonctionnellement() qui fait la validation fonctionnelle.
    Ensuite, mon contrôleur gère les deux appels l'un après l'autre avec les contrôles qui vont bien.
    Êtes-vous d'accord ?



    Autre interrogation sur les bonnes pratiques :

    Jusqu'à présent, je faisais une validation avec nettoyage des données. Dans les méthodes proposées, je ne vois pas de nettoyage (que le problème soit technique ou fonctionnel - je ne veux pas envoyer à l'insertion une valeur en dehors des valeurs possibles).
    Comment on s'y prend selon vous ? Où récupère-t-on dans les classes proposées les valeurs nettoyées ? Dans le contrôleur à l'analyse des messages de retour ?


    D'avance merci pour tous vos retours !
    De manière générale, on notera bien que dans mon exemple on manipule des FieldValidators. Rien n'empêche au demeurant d'écrire et d'injecter au FieldValidator un BaseValidatorNotNull (qui implémente l'interface déjà écrite IValidator, j'y avais un peu pensé) qui en gros se chargera de vérifier qu'une valeur n'est pas nulle. Ca nécessite de refactorer un peu mon code pour n'avoir à écrire qu'une fois la gestion des messages d'erreur (règle d'or 2 : pas de redondance de code; la règle d'or 1 étant : programmez des interfaces, pas des implémentations).

    Du coup, dans l'idée, un FieldValidator manipulera une liste de BaseValidators qui implémentent IValidator. Pour le traitement concret, le principe est similaire à la méthode validate() de la classe Form.

    En tous les cas, pas la peine de distinguer un validateur technique d'un validateur fonctionnel, ça n'a pas de grand intérêt pratique.

    Si vraiment tu veux le faire, n'appelle surtout pas tes méthodes distinctes au niveau du contrôleur. Ces méthodes doivent être appelées par le Validator, dans la méthode isValid(). Le principe est : seul un Validator valide.

    Pour l'instanciation, dans un premier temps tu peux tout instancier à la main dans le controleur, puis une fois que tu maîtrises un peu tu utilises des factories pour éviter d'écrire des tonnes de new.

    Le nettoyage ne doit pas être fait au niveau de la validation, c'est un traitement spécifique. J'ai tendance à appeler ça des filtres même si ça prête à confusion avec les filters JEE.
    A priori, il est plus intéressant de valider des valeurs déjà filtrées puisque c'est ce que tu auras à traiter.

    Niveau bonnes pratique, je me suis fixé la règle suivante :

    Si j'ai besoin d'une classe, alors je commence par écrire une interface et sa première implémentation abstraite si je n'en dispose pas déjà.

  18. #18
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    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
    Points : 7 762
    Points
    7 762
    Par défaut
    En tous les cas, pas la peine de distinguer un validateur technique d'un validateur fonctionnel, ça n'a pas de grand intérêt pratique.
    En effet, ce n'est pas mandataire, cela étant, c'est sexy de présenter à l'utilisateur une erreur de la forme : "Email is mandatory" si vide et "Not a valid Email" si mail invalide plutôt qu'un simple message d'erreur "Invalid Email field".

    Voilà comment je verrai les choses, les validateur devraient être des Iterator qu'on irait greffer sur un ObjectArray caractérisant $_REQUEST (merci SPL), on attacherait à ces validateurs des validateurs de champs génériques ou des closures pour les champs qu'on souhaite valider. Ainsi on pourrait "stacker" les validateurs et obtenir une granularité très fine selon le niveau de détails que l'on souhaite.

    ça 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
     
    class FormValidator extends FilterIterator  {
     
    	protected $_validators;
    	protected $_invalid = array();
    	protected $_valid = array();
     
    	public function __construct (Iterator $it, $validators = array()) {
    		parent::__construct($it);
     
    		if (!empty($validators)) $this->_validators = $validators;
    	}
     
    	public function registerValidator ($field, $validator) {
    		if (is_array($field))
    		{
    			foreach ($field as $f) { $this->registerValidator($f, $validator); }
    			return $this;
    		}
    		$this->_validators[$field] = $validator;
    		return $this;
    	}
     
    	public function accept () {
    		$k = $this->getInnerIterator()->key();
    		$v = $this->getInnerIterator()->current();
     
    		if (isset($this->_validators[$k]))
    		{
    			($r = $this->_validators[$k]($v)) ? $this->_valid[] = $k : $this->_invalid[] = $k;
    			return $r;
    		}
    		$this->_valid[] = $k;
    		return true;
    	}
     
    	public function applyFilter ()
    	{
    		foreach ($this as $key => $value);
    	}
     
    	public function getInvalidEntries () { return $this->_invalid; }
    	public function getValidEntries () { return $this->_valid; }
    }
    Et on va faire quelques tests:
    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
     
    $post_values = array(
    	"name" => "toto", 
    	"surname" => "titi", 
    	"mail" => "toto@titi.com");
     
    $post = new ArrayObject($post_values);
     
    $fv = new FormValidator($post->getIterator());
    $fv->registerValidator("name", function($v) { return !empty($v); }) // vérifie que name n'est pas vide
       ->registerValidator("surname", function($v) { return strpos($v, 'abc') !== false; })  // test si la valeur surname contiend 'abc'
       ->registerValidator("mail", function($v) { return preg_match('#[a-z\._\-]+@[a-z]+\.[a-z]{1-3}#i', strtolower($v)) === 1; }) // valide le champ mail
       ->applyFilter();
     
    var_dump($fv->getInvalidEntries());
    Produit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    array(2) { [0]=>  string(7) "surname" [1]=>  string(4) "mail" }
    C'est tout à fait ce à quoi on s'attendait, maintenant on va chaîner les itérateurs:
    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
     
    $post_values = array(
    	"name" => "", 
    	"surname" => "abc", 
    	"mail" => "toto.org");
     
    $post = new ArrayObject($post_values);
     
    $fv = new FormValidator($post->getIterator());
    $fv->registerValidator(array("name", "surname", "mail"), function($v) { return !empty($v); });
     
    $fv2 = new FormValidator($fv);
    $fv2->registerValidator("surname", function($v) { return strpos($v, 'abc') !== false; })  // test si la valeur surname contiend 'abc'
        ->registerValidator("mail", function($v) { return preg_match('#[a-z\._\-]+@[a-z]+\.[a-z]{1-3}#i', strtolower($v)) === 1; }) // valide le champ mail
        ->applyFilter();
     
    echo "<pre>";
    var_dump($fv->getInvalidEntries());
    var_dump($fv2->getInvalidEntries());
    echo "</pre>";
    On obtient:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    array(1) {
      [0]=>
      string(4) "name"
    }
    array(1) {
      [0]=>
      string(4) "mail"
    }
    Bon, ce n'est qu'on proof of concept qui montre ce qu'on peut faire avec les closures et les itérateurs. C'est une fonctionnalité très simple qu'il faudra étendre bien entendu.

  19. #19
    Membre régulier
    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
    Points : 99
    Points
    99
    Par défaut
    Utiliser des iterators est une bonne idée.

    Par contre, j'ai tendance à penser que les closures ont tendance à "bordéliser" les applis, surtout qu'elle sont quand même très dispensables...quand tu vois le mauvais usage qui en est fait en javascript notamment...

    Pour le reste, c'est en gros l'implémentation du principe que je proposais, en stackant des validators (et donc aussi des messages de retour).

    Sinon, pour moi, tester qu'une valeur est vide ou tester qu'un email est invalide sont deux opérations de validation fonctionnelle.

  20. #20
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    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
    Points : 7 762
    Points
    7 762
    Par défaut
    C'est pas faux, après ça dépends de la philosophie que tu adoptes.

    Note que dans mon exemple, je n'utilise que les closures, il est entendu qu'utiliser des objets - portant la méthode __invoke - est la meilleure façon de faire, mais laisser à l'utilisateur la liberté de mettre ses propres fonctions également est un plus selon moi.

    Personnellement, j'ai tendance à pense que les closures font partie intégrante des méthodes RAD.

    Je me pose une question d'ailleurs: comment implémenter correctement un iterator pour une table en BDD ? J'avais pensé à utiliser PDO et ses merveilleux PDOStatement - en les rendant serialisable pour les mettre en cache d'une page à l'autre. Le but avoué étant de faire de la pagination bien sûr en rendant tout ça compatible avec les filters - ce qui dégrade les performances par rapport à des requêtes générées à la volée mais qui serait tellement plus pratique. Qu'est ce que tu en pense Jonoz ?

    Ce qui serait carrément parfait, ce serait d'avoir une gestion des bases de données cohérentes au niveau du modèle de données avec celle des fichiers - ou de n'importe quel autre wrapper. Ça permettrait d'abstraire complètement la couche de persistance du média qu'elle utilise.

    Mais on s'égare.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

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