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] Classe Abstract : problème de conception


Sujet :

Langage PHP

  1. #1
    Membre éprouvé
    Avatar de viviboss
    Profil pro
    Inscrit en
    Août 2006
    Messages
    943
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Gard (Languedoc Roussillon)

    Informations forums :
    Inscription : Août 2006
    Messages : 943
    Points : 1 248
    Points
    1 248
    Par défaut [POO] Classe Abstract : problème de conception
    Salut !!!

    Bon, là j'ai du mal. Je sais que je dois utiliser une classe Abstract, mais je ne sais pas par ou commencer.....

    Voilà, dans ma BDD, j'ai 4 tables "rendez-vous" qui contiennent le même type d'info (il s'agit d'une démarche, on a alors : R0, R1, R2, R3...... dans l'ordre des rendez-vous)

    J'ai donc décidé, pour utiliser ma base, de construire une classe par rendez-vous. Et puis j'ai remarqué, à quelques petites exceptions (notamment le nom de mes clés primaires : id_R0, id_R1....), que les types d'infos étaient les mêmes, ainsi que les traitements.... Donc, je trouvais ridicule de "dupliquer" ma classe par autant de "rendez-vous".....

    Et je me suis souvenu de la classe virtuel, me permettant de décrir un comportement "général", dont hériterait mes classes "rendez-vous"....Mais je ne sais pas trop comment m'y prendre !!!

    Voilà le code que j'ai pour l'instant :
    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
     
    class RZero extends BaseJcb implements ShowAttributs {
     
    	public $id_r0=null; 
    	public $date_intro=null; 
    	public $realise=null; 
    	public $id_prospect=null; 
    	public $echec=null;
     
    	function __construct($id_r0, $date_intro, $realise, $id_prospect, $echec){
    		$this->id_r0=$id_r0; 
    		$this->date_intro=$date_intro; 
    		$this->realise=$realise; 
    		$this->id_prospect=$id_prospect; 
    		$this->echec=$echec;
    	}
     
    	public function tabAttributs(){
    		$attributs['id_r0']=$this->id_r0;
    		$attributs['date_intro']=$this->date_intro;
    		$attributs['realise']=$this->realise;
    		$attributs['id_prospect']=$this->id_prospect;
    		$attributs['echec']=$this->echec;
    		return $attributs;
    	}
     
    	public function insertRZero(){
     
    	}
     
    	public function updateRZero(){
     
    	}
     
    	public function deleteRZero(){
     
    	}
     
    	function __destruct(){
     
    	}
    }
    ....Et ceci par autant de rendez-vous !!!!!

    Alors je me suis dis, faisons cette classe abstraite et héritons tout ca !!!

    Mais je bloque, je ne vois pas ma démarche plus loin :
    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
     
    abstract class RGeneral extends BaseJcb implements ShowAttributs {
     
    	public $id_r=null; 
    	public $date_intro=null; 
    	public $realise=null; 
    	public $id_prospect=null; 
    	public $echec=null;
    	protected $type;//r0 ou r1 ou R2....
     
    	public function tabAttributs(){
    		$attributs['id_r']=$this->id_r;
    		$attributs['date_intro']=$this->date_intro;
    		$attributs['realise']=$this->realise;
    		$attributs['id_prospect']=$this->id_prospect;
    		$attributs['echec']=$this->echec;
    		return $attributs;
    	}
     
    	public function insertR(){
     
    	}
     
    	public function updateR(){
     
    	}
     
    	public function deleteR(){
     
    	}
     
    }
    Quelqu'un peut il m'aider, à voir, concrètement, comment utiliser une classe abstraite ?!!! (je sais, le jeux de mot concret et abstrait... )

    Merci pour votre aide futur !!!!
    Veni Vidi Vici
    -------------------------
    Mes articles : developpez.com ou bien vbview.net
    -------------------------
    Et SURTOUT ne pas oublier la bible PHP : --> php_manual_fr.chm!!!
    Et aussi : --> pear_manual_fr.chm!!!

    Ou encore : --> Les tutoriaux & cours PHP de Développez.com
    -------------------------

  2. #2
    NoT
    NoT est déconnecté
    Membre actif
    Profil pro
    Inscrit en
    Février 2004
    Messages
    237
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 237
    Points : 280
    Points
    280
    Par défaut
    Salut,

    T'as besoin de tes 4 tables pour gérer exactement le même genre de données ?
    T'as l'air d'aimer les trucs compliqués quand même

  3. #3
    Membre actif
    Profil pro
    Développeur Web
    Inscrit en
    Septembre 2006
    Messages
    215
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Septembre 2006
    Messages : 215
    Points : 256
    Points
    256
    Par défaut
    Salut


    Tu crées une classe abstraite, donc elle ne pourra par etre instancié, ok, maintenant toutes tes classes comportent les meme methodes qui doivent imperativement etre dans tes classes enfants ?? donc ces methodes aussi doivent etre abstraite
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    abstract public function insertR();
    m'enfin dans ton cas, peut etre que des methodes static et jouer avec les parametres aurais suffit non ?

  4. #4
    Membre éprouvé
    Avatar de viviboss
    Profil pro
    Inscrit en
    Août 2006
    Messages
    943
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Gard (Languedoc Roussillon)

    Informations forums :
    Inscription : Août 2006
    Messages : 943
    Points : 1 248
    Points
    1 248
    Par défaut
    Voici les codes que j'ai pondu ce matin : (ca m'a fait mal.... )

    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
     
    /************************************************************************************************
     * Classe abstraite définissant en général les rendez vous (R), et forcant la redéfinition des
     * méthodes __construct et __destruct.
     * Classe abstraite héritant de BaseJcb, implémente l'interface ShowAttributs
     * Les autres méthodes (public) sont des délégués des classes enfant
     *
     ***********************************************************************************************/
     
    abstract class RGeneral extends BaseJcb implements ShowAttributs {
     
    	/**
    	 * Force la définition de la méthode __construct, initialise différents attributs
    	 *
    	 * @param unknown_type $id_r
    	 * @param unknown_type $date_intro
    	 * @param unknown_type $realise
    	 * @param unknown_type $id_prospect
    	 * @param unknown_type $echec
    	 * @param unknown_type $type
    	 */
    	abstract protected function __construct($id_r,$date_intro,$realise,$id_prospect,$echec,$type);
     
    	/**
    	 * Méthode de listage des attributs, sous forme de tableau. Permet une manipulation aisée des attributs
    	 *
    	 * @return attributs[]
    	 */
    	public function tabAttributs(){
    		$attributs['id_r']=$this->id_r;
    		$attributs['date_intro']=$this->date_intro;
    		$attributs['realise']=$this->realise;
    		$attributs['id_prospect']=$this->id_prospect;
    		$attributs['echec']=$this->echec;
    		return $attributs;
    	}
     
    	public function insertR(){
     
    	}
     
    	public function updateR(){
     
    	}
     
    	public function deleteR(){
     
    	}
     
    	/**
    	 * Force la définition de la méthode __destruct
    	 *
    	 */
    	abstract protected function __destruct();
     
    }
    Et l'une des classes enfant :

    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
     
    /*****************************************************************
     * Classe de R0, héritant de la classe abstraite RGeneral.
     * Permet la manipulation de données concernant la table R0
     * Prend en parmètre les champs de la table R0
     *
     ****************************************************************/
     
    class RZero extends RGeneral  {
     
    	public $id_r=null; 
    	public $date_intro=null; 
    	public $realise=null; 
    	public $id_prospect=null; 
    	public $echec=null;
    	//Type de rendez vous
    	public $type=0;
     
    	/**
    	 * Constructeur de la classe RZero, intialisant différents attributs
    	 *
    	 * @param unknown_type $id_r
    	 * @param unknown_type $date_intro
    	 * @param unknown_type $realise
    	 * @param unknown_type $id_prospect
    	 * @param unknown_type $echec
    	 * @param unknown_type $type
    	 */
    	protected function __construct($id_r, $date_intro, $realise, $id_prospect, $echec,$type){
    		$this->id_r=$id_r; 
    		$this->date_intro=$date_intro; 
    		$this->realise=$realise; 
    		$this->id_prospect=$id_prospect; 
    		$this->echec=$echec;
    		$this->type=$type;
    	}
     
    	/**
    	 * Destructeur de la classe RZero
    	 *
    	 */
    	protected function __destruct(){
     
    	}
    }
    Qu'est ce que vous en pensez ?
    Veni Vidi Vici
    -------------------------
    Mes articles : developpez.com ou bien vbview.net
    -------------------------
    Et SURTOUT ne pas oublier la bible PHP : --> php_manual_fr.chm!!!
    Et aussi : --> pear_manual_fr.chm!!!

    Ou encore : --> Les tutoriaux & cours PHP de Développez.com
    -------------------------

  5. #5
    Membre éprouvé
    Avatar de viviboss
    Profil pro
    Inscrit en
    Août 2006
    Messages
    943
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Gard (Languedoc Roussillon)

    Informations forums :
    Inscription : Août 2006
    Messages : 943
    Points : 1 248
    Points
    1 248
    Par défaut
    Personne n'est capable de me dire si je suis sur la bonne voie ?!!!!!
    Veni Vidi Vici
    -------------------------
    Mes articles : developpez.com ou bien vbview.net
    -------------------------
    Et SURTOUT ne pas oublier la bible PHP : --> php_manual_fr.chm!!!
    Et aussi : --> pear_manual_fr.chm!!!

    Ou encore : --> Les tutoriaux & cours PHP de Développez.com
    -------------------------

  6. #6
    Expert éminent Avatar de Mr N.
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    5 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 5 418
    Points : 6 449
    Points
    6 449
    Par défaut
    Pour mieux analyser ton code et répondre à tes questions, je monte d'un niveau d'abstraction: Quelles sont les différences entre un rendez-vous R0 et un redez-vous R1 ?

    Sinon concernant ton code, pourquoi ton constructeur est protected ? et pourquoi abstract ?

  7. #7
    Membre éprouvé
    Avatar de viviboss
    Profil pro
    Inscrit en
    Août 2006
    Messages
    943
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Gard (Languedoc Roussillon)

    Informations forums :
    Inscription : Août 2006
    Messages : 943
    Points : 1 248
    Points
    1 248
    Par défaut
    Mon constructeur est protected et abstract pour "obliger" l'implémentation d'un constructeur dans mes classes enfant..... Est ce que je me trompe ?.....

    Alors, un RO est un rendez vous OBLIGATOIRE (reglme de gestion de la BDD..)
    Un R1 est un rendez vous avec collecte d'informations (papiers, surtout....)
    le R2_mandats initie une opération (déterminé par le contenu du mandat)
    Le R2_lot initie la réalisation de CETAINS processus DEFINISSANT l'opération,
    Le R3 finalise l'opération
    Le R4 finalise l'ensemble des "R"....

    Tous ces "R" ont les même type d'info (date rendez vous, description....) mais entrainent des actions différentes.....

    Au niveau de ma BDD je les ai différenciés, mais je suis en trains de me poser la question sur la conception : dois-je tous réunir en BDD, et gérer les spécificités avec ma logique applicative ? Ou garder cette architecture, qui me permet de structurer pas mal la démarche ?

    Merci pour votre aide !!!

    PS : si je parle beaucoup de ma BDD, c'est parce qu'elle représente ma principale source d'attributs pour les classes, et qu'elle fournit la structure de mes "premières classes"....Est ce que cette démarche est correct ?

    [EDIT]Effectivement, le protected n'est pas justifié, merci MRN
    Veni Vidi Vici
    -------------------------
    Mes articles : developpez.com ou bien vbview.net
    -------------------------
    Et SURTOUT ne pas oublier la bible PHP : --> php_manual_fr.chm!!!
    Et aussi : --> pear_manual_fr.chm!!!

    Ou encore : --> Les tutoriaux & cours PHP de Développez.com
    -------------------------

  8. #8
    Expert éminent Avatar de Mr N.
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    5 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 5 418
    Points : 6 449
    Points
    6 449
    Par défaut
    Perso je serais parti dans cette direction :
    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
    abstract class RDV {
       public function __construct($id, $date_intro, $realise, $id_prospect, $echec) {
          $this->id          = $id; 
          $this->date_intro  = $date_intro; 
          $this->realise     = $realise; 
          $this->id_prospect = $id_prospect; 
          $this->echec       = $echec;
       }
     
       public function insert(){
          mysql_query("INSERT INTO rdv (id, ..., type) VALUES 
             (". $this->id .", ..., '". get_class($this) ."')");
       }
     
       public function update(){
          mysql_query(...);
       }
     
       public function delete(){
          mysql_query(...);
       }
     
       public function __destruct() {
          ...
       }
    }
    Puis :
    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
    class RZero extends RDV {
       public function je_suis_obligatoire() {
          ...
       }
    }
     
    class RUn extends RDV {
       public function collecter_des_informations() {
          ...
       }
    }
     
    class RDeux_Mandats extends RDV {
       public function initier($operation) {
          ...
       }
    }
    ...

  9. #9
    Membre éprouvé
    Avatar de viviboss
    Profil pro
    Inscrit en
    Août 2006
    Messages
    943
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Gard (Languedoc Roussillon)

    Informations forums :
    Inscription : Août 2006
    Messages : 943
    Points : 1 248
    Points
    1 248
    Par défaut
    A ce moment là, la définition de la classe abstraite permet juste d'empêcher son instanciation ?

    Effectivement, ca a l'air plus "cool" comme architecture que la mienne, beaucoup trop "rigide" !!!! (Et finalement, je ne suis pas sûr qu'elle aurait été viable....)

    Je viens de changer l'architecture de ma BDD afin de m'adapter à l'architecture de ma classe abstraite, et c'est beaucoup plus logique !!!

    Merci Mr N !!!!

    Au niveau de la conception, est il bien que je parte de l'analyse de ma BDD ?

    PS : je suppose que quand tu met : class RZero, tu veux dire Class RZero extends RDV
    Veni Vidi Vici
    -------------------------
    Mes articles : developpez.com ou bien vbview.net
    -------------------------
    Et SURTOUT ne pas oublier la bible PHP : --> php_manual_fr.chm!!!
    Et aussi : --> pear_manual_fr.chm!!!

    Ou encore : --> Les tutoriaux & cours PHP de Développez.com
    -------------------------

  10. #10
    Expert éminent Avatar de Mr N.
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    5 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 5 418
    Points : 6 449
    Points
    6 449
    Par défaut
    Oups oui. Aux temps pour moi. class RZero extends bien RDV

    Quand à ta base je suis curieux de voir ton nouveau schéma.

    Par contre j'estime que c'est la bd qui doit s'adapter au code et pas l'inverse.

  11. #11
    Membre éprouvé
    Avatar de viviboss
    Profil pro
    Inscrit en
    Août 2006
    Messages
    943
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Gard (Languedoc Roussillon)

    Informations forums :
    Inscription : Août 2006
    Messages : 943
    Points : 1 248
    Points
    1 248
    Par défaut
    Citation Envoyé par Mr N.
    Par contre j'estime que c'est la bd qui doit s'adapter au code et pas l'inverse.
    Lol. Tu voulais dire l'inverse, je suppose....

    Mias je sais, mais là c'était un cas un peu spécial.....Je n'ai redisigné qu'une partie, qui devient du coup beaucoup plus naturel (j'étais bloqué dans une logique qui n'était pas la bonne, et qui pretait à confusion....)

    Dès que j'ai finit de redessiner le modèle, je le mettrais en PDf

    Merci MRN !!!
    Veni Vidi Vici
    -------------------------
    Mes articles : developpez.com ou bien vbview.net
    -------------------------
    Et SURTOUT ne pas oublier la bible PHP : --> php_manual_fr.chm!!!
    Et aussi : --> pear_manual_fr.chm!!!

    Ou encore : --> Les tutoriaux & cours PHP de Développez.com
    -------------------------

  12. #12
    Expert éminent Avatar de Mr N.
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    5 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 5 418
    Points : 6 449
    Points
    6 449
    Par défaut
    Citation Envoyé par viviboss
    Lol. Tu voulais dire l'inverse, je suppose....
    Non. Je persiste et je signe. Ton schéma de bd découle de ton implémentation.

    La BD gère la persistence de tes données. Tu peux très bien vouloir changer vers un système de persistance à base de fichiers... ou de cartes perforées... Donc le système de persistence ne doit pas influer sur la conception de la partie "métier" de ton système.

    Donc le raisonnement est le suivant.

    1. Besoin: Une personne possède un nom et un prénom
    2. Conception: class Personne { var $nom; var $prenom; }
    3. Si je stocke dans un SGBDR: personnes(nom, prenom);
      Si je stocke dans un flux xml: <personne nom="" prenom="" />
      Si je stocke sur cartes perforées: --. . .-. ... --- -. -. .
      etc...


  13. #13
    Membre éprouvé
    Avatar de viviboss
    Profil pro
    Inscrit en
    Août 2006
    Messages
    943
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Gard (Languedoc Roussillon)

    Informations forums :
    Inscription : Août 2006
    Messages : 943
    Points : 1 248
    Points
    1 248
    Par défaut
    Alors là, je reste Quoi .....

    Je pensais bien au contraire que l'évolution d'une appli devait se concentrer sur la modularité de la partie "logique" et "conception", et aussi "interface client".....

    Je pensais bien au contraire la partie les plus "stable" d'une appli, était son stockage de données.....

    Me suis-je fourvoyé ????!!!!!

    Je veux dire, si demain je veux implanter de nouvelles fonctionnalités à mon appli, je vais la programmer : donc articulation autour du système de données existantes.....

    Moi j'ai fait la démarche inverse, mais à priori ca ne boulversera pas trop l'ordre des choses : le tout sera quand même modulaire....

    Mais bon, je n'abordais pas les choses sous cette angle..... Mon analyse part d'abord du flux de données, car c'est cela que je vais traiter avec mon appli.... Viens ensuite les règles de gestion (partie strictement logique pour la manipulation des "contraintes"), et enfin la couche de présentation (mais cette partie reste toujours dans un coin, car elle est TRES TRES importante : c'est par celle-ci que le client sera satisfait ou non !!!)

    Bref, je partais toujours du "brut" vers le fin et complexe..... Sur le papier, ca parait pourtant juste : je ne vais développer la logique avant le flux de données que la logique est censé traiter ?!?!
    Veni Vidi Vici
    -------------------------
    Mes articles : developpez.com ou bien vbview.net
    -------------------------
    Et SURTOUT ne pas oublier la bible PHP : --> php_manual_fr.chm!!!
    Et aussi : --> pear_manual_fr.chm!!!

    Ou encore : --> Les tutoriaux & cours PHP de Développez.com
    -------------------------

  14. #14
    Expert éminent Avatar de Mr N.
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    5 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 5 418
    Points : 6 449
    Points
    6 449
    Par défaut
    Ce qui me gene, en fait, c'est que tu parles de base de données, de tables, ...
    Quand tu dis que ton client va te demander une nouvelle fonctionnalité, il va pas te dire "Je veux une colonne 'hauteur' dans la table 'maison'". Il va plutot te dire "J'aimerais renseigner et afficher la hauteur d'une maison dans sa description". non ?

    Là tu en déduit que l'objet maison se voit rajouter un attribut 'hauteur'. C'est un attribut simple, un entier qui peut être stocké dans une colonne de la table maisons.

    Maintenant ton client te dit : "Mais ma maison est occupée (ou non) par plusieurs habitants."
    Tu fais quoi ? Tu rajoutes une colonne à la table maison ? Tu crées une nouvelle table ? Comment justifies-tu un tel choix ?
    En fait tu reprends ton diagramme uml, tu rajoutes ton objet Habitant et tu crées une association entre Maison et Habitant : Une maison est habitée ou non par des habitants (relation 0..*) et un habitant habite ou pas plusieurs maisons (relation 0..*)
    Là une regle de bonne construction de schéma de bd te dis que pour une relation multivaluée, on doit créer une table supplémentaire :
    maisons(id, hauteur)
    habitants(id, nom, prenom)
    habitants_maisons(habitant_id, maison_id)

    Si tu pars de ce schéma de bd pour construire ton code, est-ce que tu vas construire un objet HabitantMaison ? Je ne pense pas, tu auras simplement tes deux objets Maison et Habitant, avec des ralations entre chaque (collection d'habitant ou collection de maisons)


    Certes les données sont stables. Mais il y a deux sortes de fonctionnalités (un peu comme les chasseurs) :
    - celles qui ne modifient rien d'autre que le code (calcul de tva, modification de l'ihm)
    - celles qui modifient le schéma de ta base. et là que tu partes de ta bd pour construire le code ou que tu fasses l'inverse ne changera rien puisqu'il te faudra de toutes façons changer ton schéma.

    et enfin la couche de présentation
    Tu dis "tres tres importante" et pourtant tu la mets à la fin. Justement, parce que c'est important, cette couche devrait être la première à être implémentée sous forme de maquette certes, mais un client validera plus facilement un choix d'ergonomie, une fonctionnalité plutot qu'un schéma sql

    je ne vais développer la logique avant le flux de données que la logique est censé traiter ?!?!
    Une maquette, c'est la version light de ton application, juste la partie présentation. Si tu es capable de produire une interface sans base de données qui tourne derrière (sinon c'est plus une maquette), alors tu es capable de produire la couche logique de ton application sans base de données derrières.
    C'est là qu'entrent en jeux les tests unitaires et les méthodes de développement telles que TDD : grâce a des frameworks de tests comme SimpleTest ou phpunit qui offrent des objets "fantaisies" (mock objects), tu peux simuler des parties de ton appli comme par exemple l'accès à ta couche de données.
    Mais bon c'est un autre sujet...

    Disclaimer: Ceci reflète bien entendu que mon opinion personnelle. En aucun cas ce sont des règles absolue et universelle. La meilleure méthode de travail est celle dans lequel on est à l'aise.

  15. #15
    Membre éprouvé
    Avatar de viviboss
    Profil pro
    Inscrit en
    Août 2006
    Messages
    943
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Gard (Languedoc Roussillon)

    Informations forums :
    Inscription : Août 2006
    Messages : 943
    Points : 1 248
    Points
    1 248
    Par défaut
    Merci en tout cas pour tes éclaircissement, je veux rester le plus objectif sur ces points de vues d'analyses, mais plus j'ai d'infos de ce type, mieux je pourrais me faire une idée sur la ou les meilleures méthodes !!!! Donc ce que tu me dis va me faire changer de comportement : je ne vais pas forcément tout prendre, mais en tout cas ce qui me semble utile à moi....

    Peux tu en dire plus sur les test dont tu parles à la fin ?

    PS : je joint mon shéma de bdd en PDF, si tu pouvais me dire ce que tu en pense....

    Merci à toi, tout cela va m'aider à éttendre ma vue sur la conception d'appli (sur ce projet, je dois en plus faire du RIA avec des Web Services, donc plus blindé est l'appli en terme de conception, plus facilement je pourrais intégrer tout ca....)
    Images attachées Images attachées
    Veni Vidi Vici
    -------------------------
    Mes articles : developpez.com ou bien vbview.net
    -------------------------
    Et SURTOUT ne pas oublier la bible PHP : --> php_manual_fr.chm!!!
    Et aussi : --> pear_manual_fr.chm!!!

    Ou encore : --> Les tutoriaux & cours PHP de Développez.com
    -------------------------

  16. #16
    Expert éminent Avatar de Mr N.
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    5 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 5 418
    Points : 6 449
    Points
    6 449
    Par défaut
    Citation Envoyé par viviboss
    Peux tu en dire plus sur les test dont tu parles à la fin ?
    http://en.wikipedia.org/wiki/Test_driven_development
    http://en.wikipedia.org/wiki/Unit_test
    Avec TDD :
    1. Tu écris un test (nouvelle fonctionnalité par exemple)
    2. Tu executes le test. Le test doit échouer et tu es donc content.
    3. Tu écris le code qui fait en sorte que le test passe.
    4. Tu executes le test (si ça passe pas tu vas en 3).
    5. Tu as un code qui tourne et dont le fonctionnement est testé. Tu nettoies le code (refactorisation), puis tu vas en 1.

    Les avantages des tests unitaires =>
    1. Les tests sont écris en même temps que le code et te permettent de produire un code qui répond à ton besoin (le besoin étant codé dans le test). On peut bien sûr faire des tests unitaires après le code, mais l'esprit TDD n'est plus là : si tu fais le test après le code, il y a un risque d'être influencé par l'implémentation de la fonctionnalité et de biaiser le résultat attendu.
    2. Les tests peuvent être automatisés. Genre toutes les nuits l'ensemble des jeux de tests sont lançés et tu reçois un mail quand un des tests échoue. Cette automatisation permet la non-regression. Si tu modifies un point A et que plus loin dans l'application un point B dépendait de ce point A alors tu seras prévenu.
    3. ça documente ton appli. - Comment utiliser cette classe ? - Regarde dans ce test, on passe tels parametres, ça fournit ça en sortie. - Cool.
    4. Ca aide à la conception et au prototypage. Grâce aux mock objects tu peux développer une classe entière qui dépend d'autres classes sans que ces dernières aient besoin d'être implémentées.
    5. Surement d'autres...

    Les inconvenients =>
    - Plus couteux en temps de développement. Mais il suffit alors de ne tester que ce qui est utile et c'est de toute façon vite contrebalancé par l'aspect "test automatisé".

    Voir SimpleTest ou PHPUnit pour les tests unitaires avec PHP

    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class Article {
       var $prix_unitaire;
       var $poids;
       function __construct($pu, $poids) {
          $this->prix_unitaire = $pu;
          $this->poids = $poids;
       }
    }
    Je veux une methode qui me retourne le prix total (pu x poids). Le test :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class TestArticle extends UnitTest {
       function testPrix() {
          $a = new Article(2, 10);
          $this->assertEqual($a->getPrix(), 20);
       }
    }
    Si on lance le test ça plante, cool. Sinon (ça arrive) faudrait se poser des questions. Ici c'est parce que la méthode getPrix() n'existe pas.
    Je rajoute la méthode dans Article :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    function getPrix() {
    }
    Si on lance le test, ça plante toujours. Normal y a rien dans la méthode.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    function getPrix() {
       return $this->prix_unitaire * $this->poids;
    }
    Ca plante plus ! On peut passer à la fonctionnalité suivante
    Dans 3 mois, on voudra, pour une raison ou une autre, modifier le code de getPrix. Genre enlever 10%. Et bien non. Le test sera là pour dire que cette modif ne passe pas. Il faudra soit trouver une autre façon de faire pour avoir ces 10% (nouvelle méthode?) soit modifier le test et ancrer ces 10% dans le code existant... Là l'exemple est simplissime, mais dans des système complexes qui mettent en jeu une demi douzaine d'objets, en modifier 1 implique de tester les autres... Manuellement c'est très cher, ou alors baclé (ou les deux). Alors qu'avec les tests unitaires un click sur un bouton et c'est testé

    Citation Envoyé par viviboss
    PS : je joint mon shéma de bdd en PDF, si tu pouvais me dire ce que tu en pense....
    Ca c'est du schéma avec des clés réferentielles comme je les aiment bien (ironie du soir...)
    C'est difficile de commenter un schéma sans savoir sur quoi il se base et à quels besoins il répond
    Quand bien même je préfère les diagrammes de classe uml bien moins concret Donc sans connaitre le cahier des charges je ne peux te dire si tu as fait une grosse boulette ou non.

  17. #17
    Expert éminent Avatar de Mr N.
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    5 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 5 418
    Points : 6 449
    Points
    6 449
    Par défaut
    Citation Envoyé par viviboss
    Peux tu en dire plus sur les test dont tu parles à la fin ?
    http://en.wikipedia.org/wiki/Test_driven_development
    http://en.wikipedia.org/wiki/Unit_test
    Avec TDD :
    1. Tu écris un test (nouvelle fonctionnalité par exemple)
    2. Tu executes le test. Le test doit échouer et tu es donc content.
    3. Tu écris le code qui fait en sorte que le test passe.
    4. Tu executes le test (si ça passe pas tu vas en 3).
    5. Tu as un code qui tourne et dont le fonctionnement est testé. Tu nettoies le code (refactorisation), puis tu vas en 1.

    Les avantages des tests unitaires =>
    1. Les tests sont écris en même temps que le code et te permettent de produire un code qui répond à ton besoin (le besoin étant codé dans le test). On peut bien sûr faire des tests unitaires après le code, mais l'esprit TDD n'est plus là : si tu fais le test après le code, il y a un risque d'être influencé par l'implémentation de la fonctionnalité et de biaiser le résultat attendu.
    2. Les tests peuvent être automatisés. Genre toutes les nuits l'ensemble des jeux de tests sont lançés et tu reçois un mail quand un des tests échoue. Cette automatisation permet la non-regression. Si tu modifies un point A et que plus loin dans l'application un point B dépendait de ce point A alors tu seras prévenu.
    3. ça documente ton appli. - Comment utiliser cette classe ? - Regarde dans ce test, on passe tels parametres, ça fournit ça en sortie. - Cool.
    4. Ca aide à la conception et au prototypage. Grâce aux mock objects tu peux développer une classe entière qui dépend d'autres classes sans que ces dernières aient besoin d'être implémentées.
    5. Surement d'autres...

    Les inconvenients =>
    - Plus couteux en temps de développement. Mais il suffit alors de ne tester que ce qui est utile et c'est de toute façon vite contrebalancé par l'aspect "test automatisé".

    Voir SimpleTest ou PHPUnit pour les tests unitaires avec PHP

    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class Article {
       var $prix_unitaire;
       var $poids;
       function __construct($pu, $poids) {
          $this->prix_unitaire = $pu;
          $this->poids = $poids;
       }
    }
    Je veux une methode qui me retourne le prix total (pu x poids). Le test :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class TestArticle extends UnitTest {
       function testPrix() {
          $a = new Article(2, 10);
          $this->assertEqual($a->getPrix(), 20);
       }
    }
    Si on lance le test ça plante, cool. Sinon (ça arrive) faudrait se poser des questions. Ici c'est parce que la méthode getPrix() n'existe pas.
    Je rajoute la méthode dans Article :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    function getPrix() {
    }
    Si on lance le test, ça plante toujours. Normal y a rien dans la méthode.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    function getPrix() {
       return $this->prix_unitaire * $this->poids;
    }
    Ca plante plus ! On peut passer à la fonctionnalité suivante
    Dans 3 mois, on voudra, pour une raison ou une autre, modifier le code de getPrix. Genre enlever 10%. Et bien non. Le test sera là pour dire que cette modif ne passe pas. Il faudra soit trouver une autre façon de faire pour avoir ces 10% (nouvelle méthode?) soit modifier le test et ancrer ces 10% dans le code existant... Là l'exemple est simplissime, mais dans des système complexes qui mettent en jeu une demi douzaine d'objets, en modifier 1 implique de tester les autres... Manuellement c'est très cher, ou alors baclé (ou les deux). Alors qu'avec les tests unitaires un click sur un bouton et c'est testé

    Citation Envoyé par viviboss
    PS : je joint mon shéma de bdd en PDF, si tu pouvais me dire ce que tu en pense....
    Ca c'est du schéma avec des clés réferentielles comme je les aiment bien (ironie du soir...)
    C'est difficile de commenter un schéma sans savoir sur quoi il se base et à quels besoins il répond
    Quand bien même je préfère les diagrammes de classe uml bien moins concret Donc sans connaitre le cahier des charges je ne peux te dire si tu as fait une grosse boulette ou non.

  18. #18
    Expert éminent Avatar de Mr N.
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    5 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 5 418
    Points : 6 449
    Points
    6 449
    Par défaut
    Citation Envoyé par viviboss
    Peux tu en dire plus sur les test dont tu parles à la fin ?
    http://en.wikipedia.org/wiki/Test_driven_development
    http://en.wikipedia.org/wiki/Unit_test
    Avec TDD :
    1. Tu écris un test (nouvelle fonctionnalité par exemple)
    2. Tu executes le test. Le test doit échouer et tu es donc content.
    3. Tu écris le code qui fait en sorte que le test passe.
    4. Tu executes le test (si ça passe pas tu vas en 3).
    5. Tu as un code qui tourne et dont le fonctionnement est testé. Tu nettoies le code (refactorisation), puis tu vas en 1.

    Les avantages des tests unitaires =>
    1. Les tests sont écris en même temps que le code et te permettent de produire un code qui répond à ton besoin (le besoin étant codé dans le test). On peut bien sûr faire des tests unitaires après le code, mais l'esprit TDD n'est plus là : si tu fais le test après le code, il y a un risque d'être influencé par l'implémentation de la fonctionnalité et de biaiser le résultat attendu.
    2. Les tests peuvent être automatisés. Genre toutes les nuits l'ensemble des jeux de tests sont lançés et tu reçois un mail quand un des tests échoue. Cette automatisation permet la non-regression. Si tu modifies un point A et que plus loin dans l'application un point B dépendait de ce point A alors tu seras prévenu.
    3. ça documente ton appli. - Comment utiliser cette classe ? - Regarde dans ce test, on passe tels parametres, ça fournit ça en sortie. - Cool.
    4. Ca aide à la conception et au prototypage. Grâce aux mock objects tu peux développer une classe entière qui dépend d'autres classes sans que ces dernières aient besoin d'être implémentées.
    5. Surement d'autres...

    Les inconvenients =>
    - Plus couteux en temps de développement. Mais il suffit alors de ne tester que ce qui est utile et c'est de toute façon vite contrebalancé par l'aspect "test automatisé".

    Voir SimpleTest ou PHPUnit pour les tests unitaires avec PHP

    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class Article {
       var $prix_unitaire;
       var $poids;
       function __construct($pu, $poids) {
          $this->prix_unitaire = $pu;
          $this->poids = $poids;
       }
    }
    Je veux une methode qui me retourne le prix total (pu x poids). Le test :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class TestArticle extends UnitTest {
       function testPrix() {
          $a = new Article(2, 10);
          $this->assertEqual($a->getPrix(), 20);
       }
    }
    Si on lance le test ça plante, cool. Sinon (ça arrive) faudrait se poser des questions. Ici c'est parce que la méthode getPrix() n'existe pas.
    Je rajoute la méthode dans Article :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    function getPrix() {
    }
    Si on lance le test, ça plante toujours. Normal y a rien dans la méthode.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    function getPrix() {
       return $this->prix_unitaire * $this->poids;
    }
    Ca plante plus ! On peut passer à la fonctionnalité suivante
    Dans 3 mois, on voudra, pour une raison ou une autre, modifier le code de getPrix. Genre enlever 10%. Et bien non. Le test sera là pour dire que cette modif ne passe pas. Il faudra soit trouver une autre façon de faire pour avoir ces 10% (nouvelle méthode?) soit modifier le test et ancrer ces 10% dans le code existant... Là l'exemple est simplissime, mais dans des système complexes qui mettent en jeu une demi douzaine d'objets, en modifier 1 implique de tester les autres... Manuellement c'est très cher, ou alors baclé (ou les deux). Alors qu'avec les tests unitaires un click sur un bouton et c'est testé

    Citation Envoyé par viviboss
    PS : je joint mon shéma de bdd en PDF, si tu pouvais me dire ce que tu en pense....
    Ca c'est du schéma avec des clés réferentielles comme je les aiment bien (ironie du soir...)
    C'est difficile de commenter un schéma sans savoir sur quoi il se base et à quels besoins il répond
    Quand bien même je préfère les diagrammes de classe uml bien moins concret Donc sans connaitre le cahier des charges je ne peux te dire si tu as fait une grosse boulette ou non.

  19. #19
    Membre éprouvé
    Avatar de viviboss
    Profil pro
    Inscrit en
    Août 2006
    Messages
    943
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Gard (Languedoc Roussillon)

    Informations forums :
    Inscription : Août 2006
    Messages : 943
    Points : 1 248
    Points
    1 248
    Par défaut
    Merci pour tous ces détails..... je vais me renseigner un peu plus en avant pour ces tests unitaires, ca me permettra de moins m'éparpiller dans mes conceptions peut être.....

    Ouai désolé pour le PDF sans explications, ca me parrait à moi évident.....

    Bref, le seul PB c'est que je cherche des outils UML gratuits et bien, et je tombe sur plein de choses dont je ne veux pas.....

    Donc pour l'instant je fais avec Visio et DBDesigner, mais si t'as un trus en UML, je suis preneur

    Le cahier des charges est le suivant (je te donne que la BDD....)
    Un collaborateur est un employé de l'entreprise pour qui je fais l'appli.
    Ces collaborateurs ont un fonctions (commercial, etc....) qui correspond à un profil dans l'appli (a le droit, pas le droit....)
    Ces collaborateurs gèrent des prospects (qui vont devenir client.....), et ces prospects sont fournit par une entreprise extérieur (peu importe....Le prospect c'est pas le collaborateur qui va le chercher....)
    Un prospect a une prise de contact avec le collaborateur (R0). Si ce R0 s'est bien passé, un R1 est donné.

    Au retour du R1, certains papiers sont à fournir, et sont introduits dans une GED (je ne m'en occupe pas....)
    Si le R1 s'est bien passé, un R2 est donné. A partir de là, le prospect devient client, et une Opération est lancé (Cette opération est composé de processus, qui sont différents selon la nature de l'opération).
    Le R2_bis continue l'opération et y intègre d'autres processus, interne à l'entreprise (envoi de papier, signatures, etc....)
    Le R3 est une finalisation de l'opération avec le client, et enfin le R4 la signature finale.

    Je dois gérer toute ces étapes, en prenant en compte les délais entre les processus, les délais limites, des alertes avec envoi d'email aux collaborateurs, ainsi que les niveaux d'attribution dans l'application. Une notion d'historique par prospect est obligatoire (toute action est historisé), et s'il y a annulation de la part du prospect (...ou client s'il le devient....) il retourne en base sous la mention "archive", et est relancé 6 mois après.

    Rien n'est supprimer en base
    Il y a des changements d'états (le prospect devient client)
    Des étapes obligatoire (un R1 ne peut être donné sans R0, s'il y a annulation il faut obligatoirement donner la raison....)

    J'avais penser à cette architecture : base, ensemble de classes manipulant les données, ensemble de classes logiques (intègre les objets de données) et enfin ensemble de classe de fourniture d'interface client (vu que c'est du RIA, il faut que je monte un service SOAP pour fournir mon interface riche)

    ->pas de limitation d'espace, l'accès est en intranet (cela dit, il y a 3 pole géographique, mais avec un VPN ca passera bien....)
    Veni Vidi Vici
    -------------------------
    Mes articles : developpez.com ou bien vbview.net
    -------------------------
    Et SURTOUT ne pas oublier la bible PHP : --> php_manual_fr.chm!!!
    Et aussi : --> pear_manual_fr.chm!!!

    Ou encore : --> Les tutoriaux & cours PHP de Développez.com
    -------------------------

  20. #20
    Expert éminent Avatar de Mr N.
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    5 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 5 418
    Points : 6 449
    Points
    6 449
    Par défaut
    Citation Envoyé par viviboss
    Donc pour l'instant je fais avec Visio et DBDesigner, mais si t'as un trus en UML, je suis preneur
    Je n'ai pas rencontré de meilleur outil que le crayon de papier et la feuille blanche. Ah si. Le tableau blanc type "weleda", plus facile à effacer et mieux pour le travail d'équipe.
    Après c'est sur que si tu veux mettre tout au propre dans un joli document word, un logiciel c'est mieux. Dans ce cas là sous linux dia est bien, si tu utilise visio c'est bien aussi. L'essentiel étant de faire quelquechose de compréhensible... Avant tout uml est un outil servant la communication.

    Citation Envoyé par viviboss
    Le cahier des charges est le suivant (je te donne que la BDD....)
    Un collaborateur est un employé de l'entreprise pour qui je fais l'appli.
    Ces collaborateurs ont un fonctions (commercial, etc....) qui correspond à un profil dans l'appli (a le droit, pas le droit....)
    Ces collaborateurs gèrent des prospects (qui vont devenir client.....), et ces prospects sont fournit par une entreprise extérieur (peu importe....Le prospect c'est pas le collaborateur qui va le chercher....)
    Un prospect a une prise de contact avec le collaborateur (R0). Si ce R0 s'est bien passé, un R1 est donné.

    Au retour du R1, certains papiers sont à fournir, et sont introduits dans une GED (je ne m'en occupe pas....)
    Si le R1 s'est bien passé, un R2 est donné. A partir de là, le prospect devient client, et une Opération est lancé (Cette opération est composé de processus, qui sont différents selon la nature de l'opération).
    Le R2_bis continue l'opération et y intègre d'autres processus, interne à l'entreprise (envoi de papier, signatures, etc....)
    Le R3 est une finalisation de l'opération avec le client, et enfin le R4 la signature finale.

    Je dois gérer toute ces étapes, en prenant en compte les délais entre les processus, les délais limites, des alertes avec envoi d'email aux collaborateurs, ainsi que les niveaux d'attribution dans l'application. Une notion d'historique par prospect est obligatoire (toute action est historisé), et s'il y a annulation de la part du prospect (...ou client s'il le devient....) il retourne en base sous la mention "archive", et est relancé 6 mois après.

    Rien n'est supprimer en base
    Il y a des changements d'états (le prospect devient client)
    Des étapes obligatoire (un R1 ne peut être donné sans R0, s'il y a annulation il faut obligatoirement donner la raison....)

    J'avais penser à cette architecture : base, ensemble de classes manipulant les données, ensemble de classes logiques (intègre les objets de données) et enfin ensemble de classe de fourniture d'interface client (vu que c'est du RIA, il faut que je monte un service SOAP pour fournir mon interface riche)

    ->pas de limitation d'espace, l'accès est en intranet (cela dit, il y a 3 pole géographique, mais avec un VPN ca passera bien....)
    Mmmmhhh...
    J'ai pas tout compris, mais plusieurs point m'interpellent.
    Ce que tu décris est un workflow tout ce qu'il y a de plus classique. Est-ce quie tu as pensé à regarder s'il existait des moteurs de workflow en php ? Peut-etre pourrais-tu t'en inspirer pour certaines briques de ton application ?
    Pourquoi y a t il echec|realise à la fois sur rdv et r_type ? Pourquoi y a t il une date sur r_type ? A ce propos, le nom 'r_type' n'est pas très explicite...
    Je comprend pas les différences entre r_type et rdv. (pourquoi prospect est sur r_type ?)

    Si je comprend bien, un rdv pris correspond à un type de rdv. A ce type de rdv sont associées des opérations (et donc des processus).
    Seulement je trouve bizarre d'attribuer des dates à des opérations qui sont liés à un type de rdv Ne manque-t-il pas la notion de type d'operation (et type de processus) ? A moins que ces dates soient NULL lorsqu'elles sont rattachées à un type... Bref pour moi c'est pas clair cette gestion de date.

    Comment sais-tu qu'un type de rdv doit être après un autre (Qu'est-ce qui m'empeche de passer de R0 à R3) ?
    ...

    Il y a trop de couplage entre commentaires et prospects. Un commentaire est lié à un rdv, qui est lié à un prospect...

    Question subsidiaire : Que ce passe-t-il si un collaborateur quitte la boite ? Les prospect existant se voient attribuer un nouveau collaborateur ? que se passe-t-il au niveau de l'historique, le nouveau collaborateur se voit attribuer les actions effectuées dans le passé par l'ancien collaborateur ?


    PS désolé pour mon triplet de hier soir

Discussions similaires

  1. Réponses: 0
    Dernier message: 09/11/2008, 14h33
  2. [débutant]Problème de conception de class
    Par pingoui dans le forum Langage
    Réponses: 23
    Dernier message: 07/04/2008, 10h30
  3. [POO] Classe d'abstraction simple
    Par sami_c dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 06/11/2007, 14h04
  4. [POO] Problème de conception POO et requêtes sql
    Par redsaint0 dans le forum Langage
    Réponses: 4
    Dernier message: 13/02/2007, 19h59
  5. [POO]Classes abstract
    Par smag dans le forum Langage
    Réponses: 5
    Dernier message: 29/06/2005, 23h05

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