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

 C++ Discussion :

Classe Utilisateur hérité


Sujet :

C++

  1. #1
    Membre extrêmement actif
    Avatar de Ryu2000
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2008
    Messages
    9 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2008
    Messages : 9 604
    Points : 18 520
    Points
    18 520
    Par défaut Classe Utilisateur hérité
    Bonjour, je réalise un logiciel sous QDevelop en ce moment.
    J'ai une classe utilisateur, une classe operateur qui est une sorte d'utilisateur, et une classe administrateur qui est une sorte d'opérateur, je pense que si ce que j'ai dis est correct vous avez compris sans que j'ai besoin de montrer le diagramme de classe.

    Au début du logiciel l'utilisateur se connecte en entrant son login et son password, après on regarde dans la base de donnée si il existe une entrée avec ce login et ce password si c'est le cas il est connecté, dans la table utilisateur de la base de donnée, il y a également un champ "Rang" qui dit si il est Utilisateur, Operateur ou Administrateur.

    Je voudrais savoir comme créer une instance d'un des 3, comme ça va ce passer au niveau du code.
    Parce que là mon code craint, j'ai déclarer une instance d'utilisateur en extern...

    Par exemple dans le code de la fenetre principal il y a ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Utilisateur2.SetLogin(Login);
    Utilisateur2.SetPassword(Password);
    Pourriez-vous m'aider s'il vous plait ?

    ================================================================

    Edit : Mon professeur vient de me dire qu'au lieu d'avoir un champ Rang de type text qui donne le Rang, c'est mieux d'avoir des bools du genre EstAdministrateur et EstOperateur.

    Je vais essayer de faire un truc du genre si le rang est utilisateur => new utilisateur et si le rang est administrateur => new administrateur, pis après faire 3 if à chaque fois qu'avant j'avais Utilisateur2.

    ================================================================

    J'ai une classe mainwindow, une classe dialog, une classe mysql, etc...
    Exemple : dans mainwindow on recupere le login et le mot de passe, on envoie ça a la classe mysql, après selon le rang on créer un new utilisateur ou new operateur.

    J'ai besoin d'avoir l'utilisateur dans la classe dialog, comment je peux faire ?
    Keith Flint 1969 - 2019

  2. #2
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2006
    Messages
    507
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Mai 2006
    Messages : 507
    Points : 704
    Points
    704
    Par défaut
    Bonjour,

    Voici une idée, qui n'est sans doute pas la meilleure, mais qui est tout de même une idée.
    Dans ta classe mainwindow par exemple tu as une variable de classe de type "pointeur vers un objet utilisateur".
    En l'ayant dans cette classe, cela permettra de transmettre les infos aux autres classes qui en ont besoin.

    Pour l'initialiser, je pense que le mieux c'est que tu es une méthode du style
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Utilisateur* login (const QString& sLogin, const QString& sPwd);
    qui soit dans ta classe "Mysql". Avec le login et le mot de passe donné, cette méthode va vérifier sur dans ta db si l'utilisateur existe, et dans ce cas trouver à quelle catégorie il appartient. A ce moment, la fonction pourra faire un "new" sur la classe appropriée et retourner le pointeur. Comme les 3 classes sont des "Utilisateurs", cela devrait fonctionner... Ainsi, le retour de la fonction (appelée depuis la classe mainwindow) peut être conservé...

    Est-ce que je suis à peu prêt clair ?

  3. #3
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Je crois que tu devrais séparer clairement les choses dans l'ordre logique d'exécution:
    1- l'utilisateur introduit (dans l'IHM) son login et son mot de passe
    2- Quand il "clique" sur le bouton ad-hoc, l'IHM envoie les informations (login et mot de passe) à la partie métier (coté client), et plus précisément à la partie qui se charge de l'envoi des requêtes au serveur
    3- la partie métier (coté client) utilise les informations reçues pour créer une requête de connexion et l'envoie au serveur

    4- (coté serveur)le serveur reçoit la requète et renvoie un résultat:
    connexion refusée (login et / ou mot de passe incorrect)
    connexion réussie : type de privilèges (utilisateur / opérateur /administrateur / ...)

    5- (retour coté client ) la partie métier récupère le résultat de la requête et
    5.a- envoie un message à l'IHM "connexion refusée" si tel est le cas
    5.a.1 - l'IHM le fait savoir à l'utilisateur et "retour" en 1
    5.b- si la connexion est acceptée, la partie métier (coté client) crée:
    5.b.1- un utilisateur "simple" si le serveur a dit qu'il acceptait l'utilisateur simple
    5.b.2- un opérateur si le serveur a dit qu'il acceptait un opérateur
    5.b.3- un administrateur si le serveur a dit qu'il acceptait un opérateur
    5.c (uniquement si passé par 5.b) envoie un message "connexion acceptée" à lIHM
    5.c.1 l'IHM fait savoir à l'utilisateur qu'il est désormais connecté

    Nous avons donc déterminé qu'il y a quatre grands acteurs dans l'histoire:
    • L'IHM: c'est la partie "vue" du MVC(*)... C'est grace à elle que l'utilisateur peut interagir avec l'application.
    • La partie métier coté client: C'est un morceau de la partie Controleur du MVC(*)
    • La partie métier coté serveur: c'est un autre morceau de la partie Controleur du MVC(*)
    • Plusieurs type d'utilisateurs : ce sont quelques types issus de la partie "modèle" du VMC(*)

    (*)MVC: Model View Controller: pour faire simple, c'est une manière de travailler qui consiste à séparer les données de la manière dont elles sont manipulées par le système et de la manière dont elles sont présentées à l'utilisateur:

    La vue (la manière dont les données sont présentées à l'utilisateur) s'adresse au controleur (à la partie qui gère les données) pour obtenir des "bribes d'informations", et le contrôleur utilise le modèle pour répondre à la vue, après s'être assuré que la vue n'essaye pas de faire une bêtise avec les données.

    Dans le controleur, nous avons remarqué la présence de deux parties distinctes: ce qui se passe du coté du client et ce qui se passe du coté du serveur.

    Généralement, il y a réellement une séparation physique entre ces deux parties (l'une travaillant sur un ordinateur et l'autre se trouvant... à l'autre bout du câble réseau).

    Il faut donc... quelque chose qui assure la connexion entre les deux.

    Nous pouvons appeler cette partie du controleur le "gestionnaire de connexion" qui se contente (coté client) d'essaye de joindre le serveur, et de maintenir la connexion active une fois qu'il y est arrivé.

    L'HIM peut lui demander à n'importe quel moment "la connexion est-elle encore active"

    (il a un autre role coté serveur, mais je vais déjà écrire un roman assez long pour éviter d'en parler ici )

    Comme il y a des communications qui doivent passer entre le client et le serveur, il faut également un système qui "formate" ces communications et qui se trouve (toujours) dans la partie controller de MVC.

    Nous appellerons ce système le "gestionnaire de requêtes".

    Son rôle (coté client, car il a aussi une utilité coté serveur) consiste à recevoir les messages que peut émettre l'IHM et qui concernent... les demandes adressées au serveur, de créer des requêtes qui seront comprises par ce dernier, de les envoyer, et de récupérer les résultats qu'il transmet "à qui de droit".

    "Qui de droit", ca peut être le retour à l'ihm ("connexion refusée / acceptée"), le gestionnaire d'utilisateur (dont je parlerai plus tard) ou un système qui recrées les données au départ de la réponse obtenue.

    Il travaille pour se faire par... la connexion maintenue par le gestionnaire de connexion



    En effet, l'utilisateur peut avoir différents droits qui sont (ou non) accordés par le serveur.

    Il faut donc pouvoir "garder en mémoire" les droits accordés, et ca, c'est le role du gestionnaire d'utilisateur.

    Un utilisateur se résume à peu de chose du coté client: on peut récupérer son login (mais pas son mot de passe ), et le GO ou le STOP pour différentes actions envisageables ( l'utilisateur peut il obtenir un catalogue, introduire une nouvelle commande, demander un devis, ajouter un nouvel article, accéder à des commandes précédentes, auxquelles, accéder à l'en-cours d'un client, duquel, ...)

    L'IHM peut, éventuellement, s'adresser à ce gestionnaire afin d'activer / de désactiver certaines options.

    As tu compris tout cela Si ce n'est pas le cas, prend un café, allume une cigarette et recommence la lecture

    C'est bon, tu a compris ... Ok, si je t'explique tout cela, c'est pour te faire prendre conscience que ton IHM ne doit pas s'inquiéter de l'utilisateur réellement connecté: elle doit "simplement" s'adresser au gestionnaire d'utilisateur pour éventuellement savoir si il a le droit de faire telle ou telle action.

    Mais comme elle devra aussi accéder aux autres gestionnaire, il lui faut donc une variable (à laquelle tous les dialogues ont accès) qui permet d'accéder à chaque gestionnaire particulier.

    Elle sera sans doute fort proche de quelque chose comme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Metier
    {
        public:
            ConnectionManager & connexion(){return con_;}
            DataManager & data(){return data_;}
            UserManager & user(){return user_;}
            RequestManager & request(){return request_;}
        private:
            ConnectionManager con_;
            DataManager data_;
            UserManager user_;
            RequestManager request_;
    };
    La classe RequestManager sera (pour ce qui est du login) proche de
    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
    class RequestManager
    {
        public:
            bool login ( std::string const & login, std::string  const & password)
            {
                /* on vérifie si la connexion est active */
                if(!con_->active())
                    throw InactiveConnexion();
                /* on peut envisager de vérifier qu'il n'y a pas quelqu'un d'autre
                 * qui est connecté :D
                 */
                if(user_->user_)
                {
                    con_->send(DisconnectUser(user_->user_->name()));
                    user_->unlog();
                }
                respons rep=con_->send(ConnectUser(login, password);
                /* si c'est pas accepté, on renvoie directment false à l'IHM */
                if(!rep->accepted())
                    return false;
                /* envoi du résultat au gestionnaire d'utilisateur et 
                 * réponse à l'IHM
                 */
                return user_->create(login, rep->userType());
            }
            void unlog()
            {
                user_->destroy();
            }
        private:
            UserManager *user_;
            ConnectionManager *con_;
    }
    Et le gestionnaire d'utilisateurs sera fort proche de
    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
    class UserManager
    {
        friend class RequestManager;
        public:
            /* une foule de fonctions renvoyant un GO ou un STOP */
            bool canDoSomething() const{return user_->canDoSomething();}
            /* éventuellement le login de l'utilisateur connecté */
            std::string const& userLogin()const{return user_->login();}
        private:
            /* accessible uniquement depuis le gestionnaire de requêtes grace
             * à l'amitié
             */
            bool create(std::string const & name, eUserType type)
            {
                switch(type)
                {
                    case user:
                        user_=new User(/* paramètres éventuels */);
                        break;
                    case ope:
                        user_= new Operator(/* paramètres éventuels */);
                        break;
                     case admin:
                        user_= new Admin(/* paramètres éventuels */);
                }
     
            }
            void destroy()
            {
                delete user_;
                user_=NULL;
            }
            User * user_;
    }
    Et, fatalement, le formulaire de connexion agira sous une forme proche de (il accède à Metier par un pointeur dont il dispose )
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void MyForm::onLoginButtonClick()
    {
        if(! Metier->request().login(champsLogin.text(), champPassword.text())
            MessageBox("impossible de se connecter");
        else
            MessageBox("vous êtes maintenant connecté");
    }
    (nota: Vu que tu travailles avec Qt, vérifie comment s'utilise QMessageBox )
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Membre extrêmement actif
    Avatar de Ryu2000
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2008
    Messages
    9 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2008
    Messages : 9 604
    Points : 18 520
    Points
    18 520
    Par défaut
    Merci beaucoup d'avoir passé autant de temps à répondre à ma question
    C'est vraiment impressionnant

    J'ai tout lu, mais je crois que je vais devoir le refaire plusieurs fois, parce qu'il y a vraiment beaucoup d'information à assimiler.
    Keith Flint 1969 - 2019

  5. #5
    Membre extrêmement actif
    Avatar de Ryu2000
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2008
    Messages
    9 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2008
    Messages : 9 604
    Points : 18 520
    Points
    18 520
    Par défaut
    En fait j'ai du mal m'éxpliquer, parce que ça je l'ai déjà fais, même si ça ne ressemble pas précisement à ça.

    L'utilisation rentre dans l'IHM, son login et son mot de passe.
    L'IHM le renvoit à la classe MySql qui renvoie 1 si l'utilisateur est présent dans la base ou 0 si ce n'est pas le cas.
    Après si MySql à renvoyé 1, l'IHM redemande à MySql le rang de l'utilisateur.
    Et l'IHM récupère le rang.

    Donc là j'arrive bien à 5.c.1 ?

    Bon par contre mon code ressemble à rien.
    Dans la classe MySql j'ai une méthode Operateur qui renvoie 1 si il est opérateur.
    Et une méthode Administrateur qui renvoie 1 si il est administrateur.

    Et du coup ça donne ç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
     
            int Connexion=MySql2.ConnexionUtilisateur(Login, Password);
    	if(Connexion==1)
    	{
    		if((MySql2.Operateur(Login) == 1) || (MySql2.Administrateur(Login) == 1))
    		{
    			if(MySql2.Operateur(Login) == 1)
    			{
    				Operateur *Operateur3 = new Operateur;
    				Operateur3->SetLogin(Login);
    				Operateur3->SetPassword(Password);
    				Operateur3->SetRang();
    			}
    			if(MySql2.Administrateur(Login) == 1)
    			{
    				Administrateur *Administrateur3 =  new Administrateur;
    				Administrateur3->SetLogin(Login);
    				Administrateur3->SetPassword(Password);
    				Administrateur3->SetRang();				
    			}
    		}
    		else
    		{
    			Utilisateur *Utilisateur3 = new Utilisateur;
    			Utilisateur3->SetLogin(Login);
    			Utilisateur3->SetPassword(Password);
    			Utilisateur3->SetRang();			
    		}
    	}
    Le truc, c'est que j'ai deux fenetres là je suis dans la mainwindows, mais après l'IHM c'est dialogimpl.

    Donc faudrait que je fasse une méthode qui renvoit l'adresse du pointeur de l'utilisateur ?
    Je voudrais dans dialogimpl, récupérer le pointeur d'utilisateur, d'operateur ou d'administrateur selon ce qui à été créé dans mainwindows, mais je ne vois vraiment pas comment faire...

    =============================================================
    J'ai repris le code d'un professeur pour les fenêtres mais apparemment, c'est pas du tout ce qu'il y a de mieux.

    Dans le main on fait int pasla=1, après il est déclaré en extern dans mainwindows et dialogimpl.

    Dans mainwindows (pour passer de mainwindows à dialogimpl):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    if (pasla)
    {
    	pasla=0;
    	DialogImpl *winfille=new DialogImpl;
    	winfille->show();
    	hide();
    }
    Dans dialoimpl (pour repasser à mainwindows) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    pasla=1;
    hide();	
    MainWindowImpl *winmere=new MainWindowImpl;
    winmere->show();
    A chaque fois c'est des nouvelles instances...
    Je devrais peut être déclarer dialogimpl dans le main, comme mainwindows, ou dire dans le .h de mainwindows qu'elle a dialogimpl dans ses arguments...

    Edit :
    J'ai éssayé tout l'après midi, mais je trouve rien du tout...
    Il y a t'il moyen qu'une instance de classe renvoie sa propre adresse ?
    Parce que dans le main il y a :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    MainWindowImpl win;	
    win.show();
    Est-ce que je pourais faire un pointeur de type MainWindowImpl avec l'adresse de win ?
    Au lieu de faire new à chaque fois, j'aimerais garder win.
    Je pense qu'après j'arriverais à faire pareil avec dialogimpl et du coup peut être régler mon problème de partage d'une instance d'utilisateur entre mainwindow et dialog.

    Oh purée, je suis en train de me dire qu'au lieu de mettre this-> si j'avais mis this j'aurais réussi tout à l'heure...

    Au final je tourne en rond.
    Je pense que si j'arrivais à garder une seule instance de mainwindow et de dialog ce serait plus simple, mais ce n'est peut être même pas le cas.
    En tout cas je créer un utilisateur dans mainwindow et je dois le récupérer dans dialog et j'y arrive pas...
    Keith Flint 1969 - 2019

  6. #6
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par thierrybenji Voir le message
    En fait j'ai du mal m'éxpliquer, parce que ça je l'ai déjà fais, même si ça ne ressemble pas précisement à ça.

    L'utilisation rentre dans l'IHM, son login et son mot de passe.
    L'IHM le renvoit à la classe MySql qui renvoie 1 si l'utilisateur est présent dans la base ou 0 si ce n'est pas le cas.
    Après si MySql à renvoyé 1, l'IHM redemande à MySql le rang de l'utilisateur.
    Et l'IHM récupère le rang.
    Pourquoi faire cela en deux temps

    Ton serveur devra sans doute gérer plusieurs connexions simultanées, et si tu dois faire deux reuqêtes ("le login existe-t-il " puis "quel est le rang de l'utilisateur qui existe "), tu augmente considérablement le risque de surcharger inutilement le serveur

    Pourquoi ne pas, simplement, renvoyer directement renvoyer:
    • 0 si l'utilisateur n'existe pas ousi le mot de passe ne correspond pas
    • 1 si c'est un utilisateur "simple"
    • 2 si c'est un "opérateur"
    • 3 si c'est un "administrateur"
    (ou toute autre possibilité de valeur cohérente)

    De toutes manières, les possibilités sont "mutuellement exclusives":
    • Si l'utilisateur n'existe pas, ou sil le mot de passe ne correspond pas, tu ne peux pas créer un utilisateur.
    • Un utilisateur simple ne peut être ni un opérateur ni un administrateur et il doit exister
    • Un opérateur est, effectivement un utilisateur, mais avec des droits particuliers, et ne peut pas être un administrateur
    • un administrateur, enfin, est effectivement un opérateur (et donc un utilisateur) mais avec encore plus de droits


    L'avantage, c'est que cela peut parfaitement être représenté sous la forme d'une énumération:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    enum eUserType
    {
        utInexistant = 0; //mauvais login ou password ne correspond pas
        utUser; // utilisateur "simple"
        utOperator; // utilisateur et opérateur
        utAdministrator; // opérateur et administrateur
    };
    Donc là j'arrive bien à 5.c.1 ?
    D'une certaine manière, oui, mais...
    Bon par contre mon code ressemble à rien.
    Dans la classe MySql j'ai une méthode Operateur qui renvoie 1 si il est opérateur.
    Et une méthode Administrateur qui renvoie 1 si il est administrateur.

    Et du coup ça donne ç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
     
            int Connexion=MySql2.ConnexionUtilisateur(Login, Password);
    	if(Connexion==1)
    	{
    		if((MySql2.Operateur(Login) == 1) || (MySql2.Administrateur(Login) == 1))
    		{
    			if(MySql2.Operateur(Login) == 1)
    			{
    				Operateur *Operateur3 = new Operateur;
    				Operateur3->SetLogin(Login);
    				Operateur3->SetPassword(Password);
    				Operateur3->SetRang();
    			}
    			if(MySql2.Administrateur(Login) == 1)
    			{
    				Administrateur *Administrateur3 =  new Administrateur;
    				Administrateur3->SetLogin(Login);
    				Administrateur3->SetPassword(Password);
    				Administrateur3->SetRang();				
    			}
    		}
    		else
    		{
    			Utilisateur *Utilisateur3 = new Utilisateur;
    			Utilisateur3->SetLogin(Login);
    			Utilisateur3->SetPassword(Password);
    			Utilisateur3->SetRang();			
    		}
    	}
    Il y a beaucoup à dire sur ce code, je vais essayer d'être bref, mais je prévois déjà de faire un roman ... va donc te servir un café, t'allumer une cloppe, faire un petit pipi, bref, prépare toi à lire les choses avec attention

    D'abord, il existe un principe nommé "Open Closed principle" qui dit que ton code doit être "ouvert aux évolutions" mais "fermé aux modifications".

    Cela signifie que tu dois veiller à ce que, une fois que ton code fonctionne, tu puisse "relativement facilement" apporter des évolutions (par exemple: ajouter des types d'utilisateur ou permettre d'utiliser d'autres types de base de données), mais que ces évolutions ne doivent pas appliquer de modifications majeures dans le code qui fonctionne.

    Par exemple, que se passerait-il si, dans trois mois, tu décidais d'abandonner MySQL au profit de MsSQL, de Oracle ou de PostGreSQL

    Pire, que se passerait-il si, encore trois mois plus tard, tu décidais de permettre à l'utilisateur de choisir d'utiliser au choix un de ces différents SGBDR

    La réponse est simple: tu devrait aller modifier le code de ta fonction, qui fonctionne pourtant correctement au risque de... produire quelque chose qui ne fonctionne plus ou qui provoque des régressions

    Une des conséquences directes de cela est un autre principe souvent connu sous le nom de "principe de la responsabilité unique"

    Pour faire simple, ce principe te dit que, si une classe ou une fonction a plus d'une responsabilité (fait plus d'une chose à chaque fois), c'est qu'elle a sans doute... trop de responsabilités.

    On peut, bien sur, discuter sur la "granularité" de ce que l'on considère comme responsabilité, mais le fait de:
    • devoir s'occuper de la saisie (du mot de passe et du login)
    • devoir s'occuper de la requête au serveur
    • devoir s'occuper de la création de l'utilisateur
    représente clairement autant de responsabilités différentes qu'il est préférable de déléguer, pas seulement en faisant des fonctions différentes dans la classe de ton formulaire, mais, carrément dans autant de classes différente:
    • s'occuper de la saisie, c'est clairement la (seule) responsabilité de l'IHM, et plus particulièrement du formulaire ad-hoc
    • s'occuper de la requête au serveur, c'est clairement le rôle... d'une classe qui centralise l'ensemble des demandes de requêtes qu'il faut exécuter, qui les formate pour le serveur et qui les envoie.
    • s'occuper de la création (et de la destruction) de l'utilisateur, voire, de la gestion des utilisateurs connectés (si tu accepte l'idée que plusieurs utilisateurs puissent être connectés en même temps depuis le même ordinateur et la même application), c'est clairement le rôle d'une classe qui... ne fait que s'occuper des utilisateurs.

    De plus, il existe un principe nommé RAII (Ressource Acquisition Is Initialization) qui conseille de faire en sorte qu'un objet soit utilisable directement après sa création, sans devoir penser à le modifier.

    Il est à mettre en relation directe avec la "loi demeter" qui conseille de n'exposer que le stricte minimum indispensable d'une classe.

    Le login d'un utilisateur, par exemple, fait partie intégrante de l'utilisateur: si tu changes le login, tu change d'utilisateur, et donc, potentiellement l'ensemble des droits dont il dispose.

    Or, lorsque le serveur accepte la connexion d'un utilisateur, il décide d'accepter la connexion parce que le login et le mot de passe correspondent (autrement, il aurait refusé la connexion), et il accorde certains droits à l'utilisateur identifié par le login... pas à un autre...

    Si tu change de login, tu dois donc avoir... un autre utilisateur, qui ne peut être créé qu'après... accord de la part du serveur.

    De la même manière, le mot de passe d'un utilisateur ne devrait jamais franchir la "barrière" que représente le serveur lorsque celui-ci répond à une requête:

    Le mot de passe d'un utilisateur est déjà présent (d'une manière ou d'une autre) sur le serveur, et c'est déjà amplement suffisant!!! Chaque endroit où ce mot de passe sera "dupliqué" représente un risque supplémentaire de voir quelqu'un (de mal intentionné)... le récupérer de manière frauduleuse

    La partie "client" de ton application, et donc a fortiori ton IHM, n'a aucun besoin de maintenir ce mot de passe en mémoire.

    Par contre, il n'est pas impossible que le serveur renvoie une information permettant d'identifier de manière unique la connexion qui sert à l'utilisateur connecté (variable de session numéro de connexion )

    La classe "utilisateur" peut (doit) sans doute disposer de cette information , mais, l'utilisateur de l'application n'a a priori aucun droit de pouvoir récupérer cette information (au travers de l'IHM) et... encore moins le droit de la modifier.

    Les fonctions setLogin, setPassword et setRang n'ont donc strictement aucun sens pour un utilisateur: ce sont autant de choses qui doivent être réglées une bonne fois pour toutes lors... de la construction de l'objet (en passant les informations au constructeur )

    Parmi ces trois fonctions, la pire, c'est setRang...

    En effet, le rang est implicite par rapport au type d'utilisateur utilisé:

    Si tu crées un "opérateur", le rang est automatiquement... celui d'un opérateur et si tu crées un "administrateur", le rang sera automatiquement... celui d'un administrateur.

    C'est, typiquement, le genre de chose qui doit être fixée une bonne fois pour toutes... au moment de la création de ton objet

    Enfin, je ne suis pas particulièrement partisan de l'utilisation des if en pagaille si je peux faire autrement: je préfères utiliser un switch case chaque fois que possible, pour la simple et bonne raison que cela peut permettre certaines optimisations dans certains cas.

    Or, il serait tout à fait possible d'envisager un switch case dans le cas présent, surtout si tu passe par une énumération, et cela te permet en outre d'assurer une certaine vérification de la réponse:
    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
    UserManager::create user(Request const & r, std::string const & login)
    {
        eUserType rang=/* récupération du rang renvoyé */
        switch(rang)
        {
            case utInexistant:
                /* ca correspond pas, un petit message et on quitte la fonction
                 */
                messageBox("login inexistant ou mot de passe ne correspond pas");
                break;
            case utUser:
                /* c'est un utilisateur simple, on crée donc... un utilisateur 
                 * simple
                 */
                m_user=new Utilisateur(login/* , paramètres éventuels */);
                break;
            case utOperator:
                /* c'est un opérateur, on crée donc... un opérateur */
                m_user=new Operateur(login/* , paramètres éventuels */);
                break;
            case utAdministrator:
                /* c'est un opérateur, on crée donc... un administrateur*/
                m_user=new Administrateur(login/* , paramètres éventuels */);
                break;
            default :
                /* toutes les autres valeurs possibles: "YAUNOS", la communication
                 * a sans doute été corrompue.
                 * on envoie un petit message, et c'est tout
                 */
                messageBox("Résultat incohérent... communication corrompue");
                break;
        }
    }
    Le truc, c'est que j'ai deux fenetres là je suis dans la mainwindows, mais après l'IHM c'est dialogimpl.
    Et alors

    Les différents gestionnaires que je te propose ne doivent même pas faire partie d'une fenêtre particulière, ou, si c'est le cas, il "suffit" de les transmettre à celles qui en ont besoin
    Donc faudrait que je fasse une méthode qui renvoit l'adresse du pointeur de l'utilisateur ?
    Non... l'utilisateur, au niveau de l'IHM, ce n'est qu'une donnée, et donc un "détail d'implémentation" qui ne devrait pas sortir de ton "gestionnaire d'utilisateur".

    Et le gestionnaire d'utilisateur se contente de répondre (par "oui" ou par "non") à des questions simple "l'utilisateur peut il commander", "peut il émettre une note de crédit","peut il rajouter de nouveaux articles","peut il ...") voire, qui renvoie une valeur énumérée dans... eUserType (selon mon exemple)...
    Je voudrais dans dialogimpl, récupérer le pointeur d'utilisateur, d'operateur ou d'administrateur selon ce qui à été créé dans mainwindows, mais je ne vois vraiment pas comment faire...
    Tu n'as pas besoin de savoir quel type réel d'utilisateur a été créé...

    Tu dois "simplement" adapter les différents comportements de l'utilisateur en fonction du type réellement utilisé...

    C'est ce que l'on appelle le polymorphisme.

    Je te conseille de te reporter à la FAQ pour savoir comment le mettre en oeuvre et ce que cela implique


    J'ai repris le code d'un professeur pour les fenêtres mais apparemment, c'est pas du tout ce qu'il y a de mieux.

    Dans le main on fait int pasla=1, après il est déclaré en extern dans mainwindows et dialogimpl.

    Dans mainwindows (pour passer de mainwindows à dialogimpl):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    if (pasla)
    {
    	pasla=0;
    	DialogImpl *winfille=new DialogImpl;
    	winfille->show();
    	hide();
    }
    Dans dialoimpl (pour repasser à mainwindows) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    pasla=1;
    hide();	
    MainWindowImpl *winmere=new MainWindowImpl;
    winmere->show();
    A chaque fois c'est des nouvelles instances...
    Je devrais peut être déclarer dialogimpl dans le main, comme mainwindows, ou dire dans le .h de mainwindows qu'elle a dialogimpl dans ses arguments...
    Avec si peu de code, il est difficile de t'aider efficacement

    Pourrais tu nous en donner un peu plus (entre autres, les définitions de MainWindowImpl et de MainWindowImpl, et la fonction main() )

    Edit :
    J'ai éssayé tout l'après midi, mais je trouve rien du tout...
    Il y a t'il moyen qu'une instance de classe renvoie sa propre adresse ?
    Parce que dans le main il y a :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    MainWindowImpl win;	
    win.show();
    oui, il y a moyen: toute fonction membre d'une classe dispose du pointeur this, qui est un pointeur sur l'objet courent
    Est-ce que je pourais faire un pointeur de type MainWindowImpl avec l'adresse de win ?
    Au lieu de faire new à chaque fois, j'aimerais garder win.
    Je pense qu'après j'arriverais à faire pareil avec dialogimpl et du coup peut être régler mon problème de partage d'une instance d'utilisateur entre mainwindow et dialog.

    Oh purée, je suis en train de me dire qu'au lieu de mettre this-> si j'avais mis this j'aurais réussi tout à l'heure...
    A l'intérieur d'une fonction membre, le recours à this est explicite (sauf quelques subtilités dont il vaut mieux ne pas parler ici ).

    Par contre, ici, tu es simplement pris d'une "diarhée mentale" occasionnée par la panique, dans laquelle il devient difficile de faire le tri (ne te méprend pas, mon but n'est pas de te vexer d'une quelconque manière... Ce n'est qu'une constatation que l'on fait souvent ) ...

    Respire un bon coup, calme toi, et essaye de nous expliquer clairement ton problème (si possible, en nous donnant un peut de code pour voir où tu te trompes )
    Au final je tourne en rond.
    Je pense que si j'arrivais à garder une seule instance de mainwindow et de dialog ce serait plus simple, mais ce n'est peut être même pas le cas.
    En tout cas je créer un utilisateur dans mainwindow et je dois le récupérer dans dialog et j'y arrive pas...
    Il est tout à fait possible de le faire...

    Mais, encore une fois, il est difficile de t'aider à y arriver sans un état des lieux complet de l'existant
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Membre extrêmement actif
    Avatar de Ryu2000
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2008
    Messages
    9 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2008
    Messages : 9 604
    Points : 18 520
    Points
    18 520
    Par défaut
    Encore une fois, je vous remercie d'avoir passé du temps pour m'aider à résoudre mes problèmes.

    Je n'ai pas donné assez d'informations...
    Seul l'administrateur peut changer le rang d'un utilisateur, mais il ne peut pas modifier son propre rang (dans le code que j'ai actuellement).

    Je sais que ce que je développe en ce moment n'est pas exportable, ce n'est pas "évoluable" non plus.
    Ce n'est pas certains que le logiciel soit terminer et fonctionnel, si c'est le cas il ne sera probablement pas utilisé, si il l'est personne ne le mettra à jour, cela dit, ce n'est pas une raison pour saboter le travail.
    Je vais essayer de mieux respecter les lois de la programmation, mais je ne suis pas très "aware" de ces lois justement ^^

    Je vais essayer de mettre en place des switchs.
    J'ai déjà mieux structurer les classes, par exemple, les méthodes de la classe utilisateur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    	void SetLogin(QString NLogin);
    	void SetPassword(QString NPassword);
    	void SetRang(QString NRang);
    	QString GetLogin();
    	QString GetPassword();
    	QString GetRang(QString Login);
    Et dans ces methodes j'appelle la classe MySql.

    Bon malheureusement, je viens de voir que SetPassword et SetRang, c'est à éviter...

    Excusez moi, mais la réponse est tellement vaste que je ne sais pas à quoi répondre.

    Je vais relire plusieurs fois...

    Ah oui au fait, je les ais viré les SetRang dans l'extrait de code que j'ai posté plus haut.
    Pis d'ailleurs je pense pouvoir virer SetPassword, j'en ais besoin que lors du changement de mot de passe.
    Keith Flint 1969 - 2019

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par thierrybenji Voir le message
    Encore une fois, je vous remercie d'avoir passé du temps pour m'aider à résoudre mes problèmes.

    Je n'ai pas donné assez d'informations...
    Seul l'administrateur peut changer le rang d'un utilisateur, mais il ne peut pas modifier son propre rang (dans le code que j'ai actuellement).
    Et encore, il le fera au niveau des autorisations que seul... la partie serveur a à gérer...

    Il faudra sans doute un formulaire "modification de rang", mais il ne devra être utilisable que si l' IHM reçoit un "go" à une question proche de "l'utilisateur peut-il modifier le rang d'un autre"

    En outre la réaction que l'IHM aura lorsqu'elle recevra le clique sur le bouton "envoyer", c'est... de demander au gestionnaire de requête d'envoyer la requête ad-hoc au serveur
    Je sais que ce que je développe en ce moment n'est pas exportable, ce n'est pas "évoluable" non plus.
    Ce n'est pas certains que le logiciel soit terminer et fonctionnel, si c'est le cas il ne sera probablement pas utilisé, si il l'est personne ne le mettra à jour, cela dit, ce n'est pas une raison pour saboter le travail.
    Exactement...

    En plus, il ne faut jamais dire "jamais" ni "fontaine je ne boirai pas de ton eau".

    Au mieux, tu sais ce qu'elle doit faire maintenant, mais il t'est quasiment impossible de prévoir exactement ce qu'on lui demandera dans... deux ou trois ans...

    Par contre, tu peux réfléchir à ce qu'on risque de lui demander dans quelques années, et faire en sorte que les évolutions soient, au minimum "pas trop difficiles à apporter"
    Je vais essayer de mieux respecter les lois de la programmation, mais je ne suis pas très "aware" de ces lois justement ^^
    n'hésite pas à demander des précisions sur les principes que j'énonce, parfois de manière un peu rapide

    Je vais essayer de mettre en place des switchs.
    Ca me semble déjà une bonne idée
    J'ai déjà mieux structurer les classes, par exemple, les méthodes de la classe utilisateur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    	void SetLogin(QString NLogin);
    	void SetPassword(QString NPassword);
    	void SetRang(QString NRang);
    	QString GetLogin();
    	QString GetPassword();
    	QString GetRang(QString Login);
    Et dans ces methodes j'appelle la classe MySql.
    Tu n'a visiblement pas compris ce que j'expliquais:
    1- le mot de passe ne doit apparaitre nulle part du coté "client" de ton application...

    Il doit "juste" y avoir un champs qui permet à l'utilisateur de l'introduire, après c'est une information dont seul le serveur doit disposer.

    Il n'y a donc aucune raison de fournir une fonction "getPassword", et encore moins de fournir le mutateur correspondant (setPassword)

    2- tu ne peux pas envisager de changer le login sans envisager de changer d'utilisateur, et donc, sans suivre un processus d'authentification...

    Il n'y a donc aucune raison valable de fournir une fonction "setLogin()"

    3- le rang (et les privilèges qui y sont associés) est (sont) déterminé(s) par le serveur en fonction des informations de connexion qui lui sont fournies.

    on ne peut donc pas non plus envisager de modifier le rang de l'utilisateur qui utilise la partie client sans envisager de passer par un processus d'authentification.

    La fonction setRang() n'a donc pas plus de raisons d'exister que la fonction setLogin ou setPassword.

    Si tu as trois rang possibles (utilisateur / opérateur / administrateur), tu peux prendre ces trois remarques en compte en créant une hiérarchie proche de
    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
    /* l'énumération sympa :D */
    enum eRank
    {
        rNoUser = 0, // l'authentification a éhcoué
        rUser,    // l'utlisateur "simple"
        rOperator, // l'opérateur, non administrateur
        rAdministrator // l'administrateur, le "dieu" du système :D
    };
    class UnIdentifiedUser// un utilisateur simple, non identifié
    {
        public:
            UnIdentifiedUser(){}
            virtual eRank rank() const {return rUser;}
            virtual QString const & login() const{return "not logged in";}
            /* éventuellement, on peut s'intéresser à certains
             * privilèges
             */
            virtual bool canHaveCatalog() const
            {
                /* même un utilisateur non identifé peut accéder au catalogue
                 */
                return true;
            }
            virtual bool canPassCommand() const
            {
                /* il faut être identifié pour passer une commande */
                return false;
            }
            virtual bool canHaveInventory() const
            {
                /* il faut "faire partie du staff" pour accéder à l'inventaire */
                return false;
            }
            virtual bool canChangRank() const
            {
                 /* seul l'administrateur peut changer le rang d'un utilisateur*/
                 return false;
            }
     
    };
    /* un utilisateur identifié est un utilisateur particulier en cela qu'on
     * dispose de son login, et qu'il a "plus de droits" qu'un utilisateur 
     * non identifié
     */
    class User : public UnIdentifiedUser
    {
        public:
            UnIdentifiedUser(QString const & l):login_(l){}
            /* on redéfini uniquement les comportements qui changent
             */
            virtual eRank rank() const {return rUser;}
            virtual QString const & login() const{return login_;}
            virtual bool canPassCommand() const
            {
                /* un utilisateur identifié peut passer une commande */
                return true;
            }
            /* par contre, l'accès au catalogue ou la possibilité de changer
             * le rang d'un utilisateur lui sont refusés...
             * les comportements définis pour UnIdentifiedUser restent donc
             * valables
             */
        private:
            QString login_; // la seule information réellement intéressante :D
     
    };
    /* un opérateur est... un utilisateur "normal" avec quelques privilèges
     * supplémentaires.
     * il peut, par exemple, accéder à l'inventaire du stock
     */
    class Operator: public User
    {
        public:
            Operator(QString const & l):User(l){}
            /* on redéfini uniquement les comportements qui changent
             */
            virtual eRank rank() const {return rOperator;}
            virtual bool canHaveInventory() const
            {
                return true;
            }
     
    };
    /* enfin, l'administrateur est... un opérateur qui a encore plus
     * de privilèges (entre autres, ceux de changer le rang des
     * utilisateurs)
     */
    class Administrator: public Operator{
        public:
            Administrator(QString const & l):Operator(l){}
            /* on redéfini uniquement les comportements qui changent
             */
            virtual eRank rank() const {return rAdministrator;}
            virtual bool canChangRank() const
            {
                 return true;
            }
     
    };
    Il y a très certainement de meilleures approches, mais celle-ci correspond à peu près à tes besoins actuels, et permet malgré tout de donner les explications adéquates

    Tu pourra en effet appeler les fonctions qui t'intéressent en profitant du polymorphisme (comprend: le comportement réellement observé dépend du type "dynamique" de l'utilisateur connecté) et donc, sans devoir te poser la question de savoir si, oui ou non, l'utilisateur actuellement connecté est un "simple" utilisateur, un opérateur ou un administrateur
    Bon malheureusement, je viens de voir que SetPassword et SetRang, c'est à éviter...
    De manière générale, les mutateurs (en anglais on parle de "seters" ) ne sont à envisager que lorsqu'il est réellement envisageable de modifier un objet sans que cela ne risque de le faire passer pour... un autre.

    Pour le mot de passe et le rang, tu aura remarqué que ce n'est pas le cas

    De la même manière, le mutateurs (en anglais on parle de "getters" ) ne sont à réellement envisager que lorsqu'ils permettent d'accéder à... des propriétés intrinsèques de l'objet (le login d'un utilisateur, par exemple, est une des données déterminante pour l'identification de l'utilisateur, et sera sans doute utilisée "à tour de bras" )
    Excusez moi, mais la réponse est tellement vaste que je ne sais pas à quoi répondre.

    Je vais relire plusieurs fois...
    Hehe... je t'avais prévenu

    N'hésite pas à demander plus d'infos sur le sujet
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #9
    Membre extrêmement actif
    Avatar de Ryu2000
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2008
    Messages
    9 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2008
    Messages : 9 604
    Points : 18 520
    Points
    18 520
    Par défaut
    Merci.
    Argh j'ai pas eu le temps de répondre !
    En fait j'ai modifié mon code, la méthode SetPassword n'existe plus.

    Dans la classe MySql, j'ai une méthode qui recoit une variable QString Login, elle regarde dans la base de donnée, l'entrée dont le champ Login est égale à cette variable et enfin elle renvoit le mot de passe.

    Parce qu'avant dans le private de la classe Utilisateur, j'avais une variable Password de type QString, en fait elle servait à rien...

    Je vais enlever la variable Rang maintenant.
    Ca y est, en fait je m'en servais pas...

    Dans l'IHM, j'ai un widget pour modifier le rang, ça le recupère et le modifie.
    Et tout marche.

    Edit :
    En fait les différents Set, servait à mettre à jour des variables dans une instance de la classe utilisateur :
    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
    #ifndef UTILISATEUR_H
    #define UTILISATEUR_H
    #include <QString>
     
    class Utilisateur  
    {
    private :
    	QString Login;
    public:
    	Utilisateur();
    	void SetLogin(QString NLogin);
    	QString GetLogin();
    	QString GetRang(QString Login);
    };
    #endif
    Avant avec Login, j'avais Rang et Password.
    Je pense avoir besoin du Login.

    ================================================================
    Je vais vous montrer quelques images, même si ça ne sert pas à grand chose.

    Ca c'est la mainwindow, normalement les champs login et password sont vides, mais comme j'ai pas envie de les re-entrer à chaque fois...


    On doit clickez sur un truc pour se connecter à la base, mais je devrais le virer, et se connecter à la base dans un constructeur.


    Là c'est quand un utilisateur se connecte :


    Là quand c'est un administrateur qui se connecte :


    Là on créer un utilisateur :
    Keith Flint 1969 - 2019

  10. #10
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par thierrybenji Voir le message
    Merci.
    Argh j'ai pas eu le temps de répondre !
    En fait j'ai modifié mon code, la méthode SetPassword n'existe plus.

    Dans la classe MySql, j'ai une méthode qui recoit une variable QString Login, elle regarde dans la base de donnée, l'entrée dont le champ Login est égale à cette variable et enfin elle renvoit le mot de passe.
    Pourquoi renvoyer le mot de passe

    Au niveau du serveur, tu dois suivre une logique proche de
    1- effectuer une requete sur la table ad-hoc qui te renvoie l'enregistrement correspondant au login reçu
    2.a- si aucun enregistrement n'est récupéré, créer une réponse "connexion refusée" (aller en 3)
    2.b- si un enregistrement est récupéré, comparer le champs "mot de passe" avec le mot de passe obtenu
    2.b.1- si le mot de passe ne correspond pas, créer une réponse "connexion refusée" (aller en 3)
    2.b.2- si le mot de passe correspond, créer une réponse "connexion acceptée"
    2.b.3- créer une "variable de session" ou connecter réellement l'utilisateur, et rajouter éventuellement les éléments utiles à la réponse
    3- renvoyer la réponse

    Parce qu'avant dans le private de la classe Utilisateur, j'avais une variable Password de type QString, en fait elle servait à rien...

    Je vais enlever la variable Rang maintenant.
    Ca y est, en fait je m'en servais pas...

    Dans l'IHM, j'ai un widget pour modifier le rang, ça le recupère et le modifie.
    Et tout marche.
    Ce que tu ne comprend décidément pas, c'est que le login et le rang sont des caractéristiques intrinsèques de tes utilisateurs:

    Quand un utilisateur est créé au niveau de l'IHM, il "reçois" un rang qui lui est accordé par le serveur, et il le garde.

    C'est comme le prénom ou le sexe d'une personne: ils sont déterminés à la naissance de la personne, et la personne n'en change (enfin, en théorie, parce que maintenant, on n'est plus sur de rien) jamais jusqu'à sa mort.

    Si tu as un utilisateur simple "alain" et que tu veux, au niveau de l'IHM, lui donner les droits d'administrateur, ce n'est plus "alain" qui est connecté, mais "quelqu'un d'autre".

    De même, "alain" n'acceptera que difficilement qu'on lui dise "maintenant, tu t'appelle caroline", parce que "alain" et "caroline" sont deux utilisateurs clairement distincts, et les droits qui y sont rattachés sont déterminés par... la partie serveur, qui a de grandes chances de se trouver à des centaines de kilomètres de l'ordinateur sur lequel s'effectue l'application.


    Edit :
    En fait les différents Set, servait à mettre à jour des variables dans une instance de la classe utilisateur :
    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
    #ifndef UTILISATEUR_H
    #define UTILISATEUR_H
    #include <QString>
     
    class Utilisateur  
    {
    private :
    	QString Login;
    public:
    	Utilisateur();
    	void SetLogin(QString NLogin);
    	QString GetLogin();
    	QString GetRang(QString Login);
    };
    #endif
    Le fait est qu'il faut fixer ces informations au moment de la construction de l'utilisateur: un utilisateur qui n'est pas identifié par un login et qui n'a pas de rang est, purement et simplement, inutilisable, et, si tu modifie une de ces informations, tu change littéralement d'utilisateur.

    Tu dois donc:
    1. t'arranger pour que l'utilisateur ne soit pas créé dés le départ (en utilisant vraisemblablement un pointeur sur utilisateur qui sera, au départ, de valeur nulle)
    2. t'arranger pour que la possibilité de création d'un utilisateur soit aussi restreinte que possible: il ne faut pas que tu puisse créer d'utilisateur selon ton "envie du moment" ni sans respecter certaines règles (par exemple, celle qui consiste à dire qu'il ne peut y avoir qu'un seul utilisateur connecté à un instant T)
    3. t'arranger pour passer directement toutes les informations nécessaires (login et rang, principalement) au moment de la création de l'utilisateur (dans son constructeur)

    A l'extrême limite, cela pourrait prendre la forme d'une classe unique proche de:
    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
     
    enume eRank
    {
        rNoUser = 0, // on ne crées pas un utilisateur de ce rang...
                     // c'est simplement une valeur qui dit que la connexion est
                     // refusée
        rUser,
        rOperator,
        rAdmin
    };
    /* la classe utilisateur */
    class User
    {
        public:
            /* les informations que l'on doit pouvoir récupérer */
            QString const & login() const{return login_;}
            eRank rank const{return rank;}
        private:
            /* on souhaite empêcher tout le monde sauf... le gestionnaire 
             *d'utilisateur de créer un utilisateur.
             *
             * Dans l'autre sens, seul le gestionnaire d'utilisateur peut détruire
             * l'utilisateur ;)
             * on peut y arriver en déclarant le constructeur privé et le
             * gestionnaire comme ami de la classe User
             */
             friend class UserManager;
             User(Qstring const & l, eRank r):login_(l), rank_(r){}
             ~User(){}
             QString user_;
             eRank rank_;
    };
    class UserManager
    {
        public:
            /* quand on crée le gestionnaire, il n'y a pas d'utilisateur */
            UserManager(RequestManager* rm):rl_(rm), user_(NULL){}
            /* quand on détruit le gestionnaire, on détruit l'utilisateur s'il 
             *existe 
             */
            ~UserManager()
            {
                if (user_)
                    rm_->logout(user->login());
            }
            /* on donne la possibilité d'enregistrer un utilisateur connecté 
             */
            bool registerUser(QString const & l, eRank r)
            {
                /* on ne peut avoir qu'un seul utilisateur connecté à chaque 
                 * fois...
                 * s'il y en a déjà un qui est enregistrer, on le déconnecte 
                 * correctement... 
                 * on va partir du principe que la fonction logout du gestionnaire
                 * de requêtes invoque directement  en invoquant 
                 * unregisterUser ;)
                 */
                if(user_)
                    rm_->logout(user->login());
                user_=new User(l, r); 
                return user_!=NULL;
            }
            /* la fonction unregisterUser: détruit l'utilisateur ;) */
            void unregisterUser()
            {
                delete user_;
                user_=NULL;
            }
            /* et on peut récupérer l'utilisateur existant */
            User const & user() const
           {
               /* sans doute le meilleur moyen pour signaler à l'IHM qu'il n'y a
                * aucun utilisateur connecté ;)
                */
               if(!user_)
                   throw NoUserConnected();
               return *user_;
           }
            /* on peut éventuellement décider de connecter un autre
             * gestionnaire de requêtes... mais c'est un autre débat
             * Le mécanisme permettant de le faire n'est pas complet,
             * et seule une petite partie est présentée ici :D 
             */
            void setRequestManager(RequestManager* r)
            {
                rm_ = r;
            }
        private:
            /* la plupart des actions prises par le gestionnaire d'utilisateur
             * doivent transiter par le gestionnaire de requêtes pour être 
             * relayées vers le serveur
             */
            RequestManager * rm_;
            /* l'utilisateur connecté */
            User * user_;
    };
    NOTA: j'ai mis énormément de commentaires... ils ne sont pas là "pour faire joli"

    Lis les attentivement
    Avant avec Login, j'avais Rang et Password.
    Je pense avoir besoin du Login.
    Oui, tu as effectivement besoin du login, tout comme tu as sans doute besoin du rang ou d'un principe similaire.

    Mais tu n'a besoin de ces informations que sous la forme d'un accès "en lecture seule": tu dois pouvoir les récupérer, mais il n'y a aucun sens à permettre de les modifier

    le getLogin et le getRang (que je présente sous les noms respectifs de fonction rank et login) sont donc utiles (et sans doute indispensables ) mais les setLogin et setRang n'ont strictement aucun sens, parce que, encore une fois, si tu modifie le login ou le rang, tu obtiens... un utilisateur totalement différent, qui doit être "validé" par la partie serveur

    Ca c'est la mainwindow, normalement les champs login et password sont vides, mais comme j'ai pas envie de les re-entrer à chaque fois...
    Commençons par nous mettre d'accord...

    Quand crois tu que tu devrais les réentrer

    Les seul moments où tu devrais le faire c'est:
    • au lancement de l'application
    • après t'être déconnecté
    Ce sont deux moments on ne peut plus logiques, et, au pire, tu ne dois pas avoir recours à la partie serveur pour retenir cela: un simple fichier texte (ini ) te permet de garder les informations de connexion de l'utilisation précédente (fais cependant attention au peu de sécurité que peut présenter le fait d'écrire un mot de passe en clair dans un fichier texte )
    On doit clickez sur un truc pour se connecter à la base, mais je devrais le virer, et se connecter à la base dans un constructeur.
    On doit toujours cliquer pour se connecter...

    C'est par le clique que la vue indique au contrôleur ce que l'utilisateur attend de lui.

    Et c'est pour cela que je te conseille de clairement séparer les différents éléments
    Là c'est quand un utilisateur se connecte :
    Et cela ne doit apparaitre que si... la connexion a réussi
    Là quand c'est un administrateur qui se connecte :
    Et l'activation ou non des différents boutons dépend du rang de l'utilisateur...

    Je t'ai montré au moins trois manières différentes d'envisager la manière de faire pour faire correspondre le rang de l'utilisateur à celui qui est accordé par le serveur
    Là on créer un utilisateur :
    Et tu ne peux y accéder que si l'utilisateur connecté a un rang suffisant (donc, si, à la base, le bouton correspondant est actif)

    Mais tu n'a absolument pas besoin de créer un utilisateur du coté client: lorsque l'administrateur clique sur le bouton "créer l'utilisateur", l'IHM s'adresse au gestionnaire de requêtes et lui demande (en gros) "envoie la requête de création d'un utilisateur avec comme login (login), comme mot de passe (mot de passe) et comme rang (rang)".

    Il y a deux raisons à cela:
    1. La création de l'utilisateur n'a de sens que parce qu'elle est... relayée au serveur, et ne devient active que si... le serveur accepte de créer l'utilisateur demandé
    2. Du coté client, l'administrateur a (sans doute) plusieurs choses à faire en plus de créer un nouvel utilisateur... il accepterait relativement mal de se retrouver connecter en tant que ce nouvel utilisateur (qui *risque* de n'avoir que des droits très restreints par rapport à ceux de l'administrateur) à chaque fois qu'il crée un nouvel utilisateur
    Au final, la partie client de l'application et l'IHM peuvent littéralement "oublier" qu'un nouvel utilisateur vient d'être créé dés qu'elle a reçue la confirmation de la part du serveur que la création a réussi.

    Au pire, elle peut garder l'information comme... historique de ce qu'a fait l'administrateur, afin qu'il puisse vérifier d'avoir effectivement fait tout ce qu'il avait à faire

    Mais, si, cinq minutes après que l'administrateur a créé un nouvel utilisateur, ce dernier vient et veut utiliser l'application, il devra commencer par... se connecter au serveur, non
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  11. #11
    Membre extrêmement actif
    Avatar de Ryu2000
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2008
    Messages
    9 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2008
    Messages : 9 604
    Points : 18 520
    Points
    18 520
    Par défaut
    SetLogin ne sert qu'a mettre le Login dans QString Login lors de la création de l'utilisateur.
    Je devrais pouvoir passer le login comme argument dans le constructeur d'un utilisateur.
    Edit : Ouais c'est bon ça marche

    Pour la création d'utilisateur, je ne faisais pas comme ça, d'ailleurs je vais peut être devoir tout changer...
    Une méthode recoit le login et le password entré dans l'ihm, et elle regarde si une entrée de la base de donnée à ce login et ce password, si c'est le cas elle retourne 1, sinon 0.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int MySql::ConnexionUtilisateur(QString Login, QString Password)
    {
    	QSqlQuery query("SELECT * FROM utilisateur");
    	int NbLogin = query.record().indexOf("Login");
    	int NbPassword = query.record().indexOf("Password");
    	while (query.next()) 
    	{
            	if((Login==query.value(NbLogin).toString()) &&  (Password==query.value(NbPassword).toString()))
            	{       	
    			return 1;
    		}
    	}
    	return 0;
    }
    Je vais essayer de répondre à vos questions :
    Quand crois tu que tu devrais les réentrer ?
    J'entre les informations de connexion, lors de la connexion, soit au lancement du logiciel, soit après qu'un utilisateur se soit déconnecté.

    Pourquoi renvoyer le mot de passe
    J'ai une methode qui renvoit le mot de passe présent dans la base de donnée, pour modifier le mot de passe, il y a une lineEdit, mot de passe actuel, si l'utilisateur n'entre pas le bon mot de passe un message d'erreur s'affiche.

    Mais, si, cinq minutes après que l'administrateur a créé un nouvel utilisateur, ce dernier vient et veut utiliser l'application, il devra commencer par... se connecter au serveur, non
    Oui pour qu'un utilisateur puisse utiliser le logiciel, il doit se connecter.
    Quand un administrateur créer un utilisateur rien ne change pour la partie client, enfin presque rien, la seule différence que c'est dans les comboBox de modifier un utilisateur et supprimer un utilisateur, l'utilisateur qui vient d'être créé apparait.


    =================================================================
    Edit: j'ai un problème avec mon héritage, voilà le .h de la classe opérateur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #ifndef OPERATEUR_H
    #define OPERATEUR_H
    //
    #include "utilisateur.h"
    //
    class Operateur: public Utilisateur
    {
     
    public:
    	Operateur();
    	Operateur(QString Nlogin);	
    };
    #endif
    Sans le constructeur Operateur(QString Nlogin) il devrait utiliser celle d'Utilisateur, non ?
    Parce que c'est pas le cas, j'ai un message d'erreur qui dis, en gros, qu'il ne connait pas de constructeur d'operateur qui recoit un qstring.
    Et si je créer le constructeur Operateur(QString Nlogin), ça me dit que QString Utilisateur::Login is private.
    Keith Flint 1969 - 2019

  12. #12
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par thierrybenji Voir le message
    SetLogin ne sert qu'a mettre le Login dans QString Login lors de la création de l'utilisateur.
    Je devrais pouvoir passer le login comme argument dans le constructeur d'un utilisateur.
    Edit : Ouais c'est bon ça marche

    Pour la création d'utilisateur, je ne faisais pas comme ça, d'ailleurs je vais peut être devoir tout changer...
    Une méthode recoit le login et le password entré dans l'ihm, et elle regarde si une entrée de la base de donnée à ce login et ce password, si c'est le cas elle retourne 1, sinon 0.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int MySql::ConnexionUtilisateur(QString Login, QString Password)
    {
    	QSqlQuery query("SELECT * FROM utilisateur");
    	int NbLogin = query.record().indexOf("Login");
    	int NbPassword = query.record().indexOf("Password");
    	while (query.next()) 
    	{
            	if((Login==query.value(NbLogin).toString()) &&  (Password==query.value(NbPassword).toString()))
            	{       	
    			return 1;
    		}
    	}
    	return 0;
    }
    Tu ne crois pas qu'il serait plus simple et plus efficace d'avoir quelque chose prenant la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int MySql::ConnexionUtilisateur(QString Login, QString Password)
    {
    	QSqlQuery query("SELECT * FROM utilisateur WHERE Login=")+Login;
    	int NbLogin = query.record().indexOf("Login");
    	int NbPassword = query.record().indexOf("Password");
    	return ( query.size()==1 && 
                     Password==query.value(NbPassword).toString())
    (non testé, mais l'idée y est )
    Je vais essayer de répondre à vos questions :

    J'entre les informations de connexion, lors de la connexion, soit au lancement du logiciel, soit après qu'un utilisateur se soit déconnecté.
    C'est marrant, c'est exactement ce que j'avais dit

    J'ai une methode qui renvoit le mot de passe présent dans la base de donnée, pour modifier le mot de passe, il y a une lineEdit, mot de passe actuel, si l'utilisateur n'entre pas le bon mot de passe un message d'erreur s'affiche.
    Ough la... Quelle soupe...

    Reprenons:

    1. Le mot de passe est "maintenu" dans la base de données, et n'a, a priori, aucune raison d'en sortir à un autre moment que lors de la connexion d'un utilisateur.
    2. Une fois que l'utilisateur est connecté, on n'a, a priori, aucune raison de lui redemander son mot de passe jusqu'à ce qu'il décide de se déconnecter.
    3. Si l'utilisateur décide de changer son mot de passe, on n'a, a priori, aucune raison de lui demander "l'ancien" mot de passe, vu que l'utilisateur est connecté, mais il faut s'assurer que le champs correspondant dans la base de données soit mis à jour
    Comme tu peux le remarquer, il n'y a aucune raison de permettre de récupérer le mot de passe de l'utilisateur, pas plus qu'il n'y a la moindre raison... de faire en sorte que l'utilisateur en dispose du coté client.

    Eventuellement, tu peux envisager de travailler en deux temps lorsque l'utilisateur décide de changer son mot de passe:
    1. vérifier "l'ancien" mot de passe, afin de s'assurer que ce n'est pas un "margoulin" qui profite du fait que l'utilisateur a le dos tourné pour changer le mot de passe
    2. mettre le mot de passe à jour
    MAIS la vérification se fait... au niveau de la base de données, et non au niveau d'un champs plus ou moins caché de l'IHM.

    Cela implique qu'il y aurait alors deux requêtes effectuées:
    • Une requête de sélection (SELECT * from utilisateur WHERE Login = login) qui vérifie que l'ancien mot de passe introduit par l'utilisateur correspond bien à celui qui est maintenu dans la base de données
    • une requête de mise à jour (UPDATE utilisateur SET Password = password WHERE Login = login )
    Comme tu peux le remarquer, l'IHM n'a absolument aucune nécessité de disposer du mot de passe de l'utilisateur: c'est très clairement une donnée qui "sort de son domaine de compétences" et de ses attributions
    Oui pour qu'un utilisateur puisse utiliser le logiciel, il doit se connecter.
    Quand un administrateur créer un utilisateur rien ne change pour la partie client, enfin presque rien, la seule différence que c'est dans les comboBox de modifier un utilisateur et supprimer un utilisateur, l'utilisateur qui vient d'être créé apparait.
    Oui, mais, de toutes manières, la liste des utilisateurs affichée par cette combobox est gérée... par les enregistrements renvoyés par une requête à la base de données...

    Il "suffit" donc de "connecter" la réussite de la création d'un utilisateur (va savoir pourquoi, mais elle peut toujours échouer ) à la mise à jour du combobox, qui envoie une requête de sélection("SELECT Login from utilisateur") à la base de données quand cet événement survient
    [/QUOTE]
    Edit: j'ai un problème avec mon héritage, voilà le .h de la classe opérateur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #ifndef OPERATEUR_H
    #define OPERATEUR_H
    //
    #include "utilisateur.h"
    //
    class Operateur: public Utilisateur
    {
     
    public:
    	Operateur();
    	Operateur(QString Nlogin);	
    };
    #endif
    Sans le constructeur Operateur(QString Nlogin) il devrait utiliser celle d'Utilisateur, non ?
    Parce que c'est pas le cas, j'ai un message d'erreur qui dis, en gros, qu'il ne connait pas de constructeur d'operateur qui recoit un qstring.
    Et si je créer le constructeur Operateur(QString Nlogin), ça me dit que QString Utilisateur::Login is private.[/QUOTE]
    Pourrais tu me montrer la classe Utilisateur, et surtout la définition du constructeur prenant ta QString

    De toute évidence, Login est un membre privé de la classe Utilisateur, et n'est donc pas accessible depuis... les fonctions membres propres de Operateur, et tu essaye d'assigner directement Nlogin depuis le constructeur de... Operateur
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  13. #13
    Membre extrêmement actif
    Avatar de Ryu2000
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2008
    Messages
    9 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2008
    Messages : 9 604
    Points : 18 520
    Points
    18 520
    Par défaut
    C'est bon j'ai été aidé pour trouver une solution et ça marche.
    Voilà la classe utilisateur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class Utilisateur  
    {
    private :
    	QString Login;
    	QString Rang;
    protected :
    	void SetLogin(QString NLogin);
    	void SetRang(QString NRang);
    public:
    	Utilisateur();
    	Utilisateur(QString NLogin);
    	QString GetLogin();
    	QString GetRang();
    };
    J'ai remis un SetLogin et un SetRang, ils sont utilisé dans les constructeurs, par exemple celui d'Operateur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Operateur::Operateur(QString NLogin) 
    {
    	this->SetLogin(NLogin);
    	this->SetRang("Operateur");
    }
    Dans le private des .h de mainwindow et dialog j'ai un pointeur utilisateur.
    Dans dialog j'ai un setteur d'utilisateur, quand je créer une instance de dialog, je lui envois l'utilisateur que j'ai créé.

    Donc voilà selon le rang dans MySql je créer une instance d'utilisateur, d'opérateur ou d'administrateur dans mainwindow et je l'envoie à dialog.
    Bon après c'est un peu du bricolage d'avoir une variable Rang, juste parce que je n'arrive pas à dire "si le pointeur utilisateur est un operateur".

    Enfin bref tout marche, j'ai viré mes extern, j'ai fais pour qu'un pointeur utilisateur = new operateur.
    C'est chouette.

    Pour la vérification du mot de passe, je fais faire une méthode qui recoit, le login du gars connecté, et le mot de passe entré et qui vérifie si c'est ça dans la base de donnée, elle retournera 0 ou 1 en fonction du résultat.

    Merci le sujet est résolu.
    Keith Flint 1969 - 2019

  14. #14
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par thierrybenji Voir le message
    C'est bon j'ai été aidé pour trouver une solution et ça marche.
    Voilà la classe utilisateur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class Utilisateur  
    {
    private :
    	QString Login;
    	QString Rang;
    protected :
    	void SetLogin(QString NLogin);
    	void SetRang(QString NRang);
    public:
    	Utilisateur();
    	Utilisateur(QString NLogin);
    	QString GetLogin();
    	QString GetRang();
    };
    Je ne suis déjà pas sur que le choix d'un QString soit réellement opportun pour représenter le rang de l'utilisateur...

    Il y a plusieurs raisons à cela:
    1. La comparaison entre chaines de caractères est particulièrement lente, car elle nécessite de comparer l'ensemble des caractères qui la composent
    2. Le couple switch... case n'est utilisable que pour comparer... des valeurs numériques entières
    3. je ne suis pas sur du tout que le rang soit sauvegardé sous la forme d'une chaine de caractères dans la base de données (ce serait typiquement plutôt une valeur numérique, non )
    4. comme l'administrateur choisit le rang de l'utilisateur qu'il crée au travers d'un combobox, il est parfaitement possible (et plus facile- de se baser sur la valeur renvoyée par la fonction selectedIndex() plutôt que sur le texte de cette valeur

    J'ai remis un SetLogin et un SetRang, ils sont utilisé dans les constructeurs,
    par exemple celui d'Operateur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Operateur::Operateur(QString NLogin) 
    {
    	this->SetLogin(NLogin);
    	this->SetRang("Operateur");
    }
    Justement, tu n'a pas à invoquer ces fonctions dans le constructeur de Operateur...

    Par contre, tu dois veiller à y invoquer le constructeur correct de Utilisateur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Operateur::Operateur(QString NLogin): 
               Utilisateur(NLogin, QString("Operateur"))
    {
    }
    Encore une fois, il faut te dire que la classe Operateur est composée en grande partie de... la classe Utilisateur, et que, lorsqu'un objet de type Operateur est créé, il ne peut l'être que parce qu'un objet de type Utilisateur l'est, et que ce dernier se doit d'être... correctement initialisé.

    Il n'y a donc aucune raison de placer une fonction setRang ou setLogin quelle que soit l'accessibilité dans laquelle tu la place
    Dans le private des .h de mainwindow et dialog j'ai un pointeur utilisateur.
    Dans dialog j'ai un setteur d'utilisateur, quand je créer une instance de dialog, je lui envois l'utilisateur que j'ai créé.
    Pourquoi faire les choses en deux temps

    Là, tu crées un utilisateur, et tu le renvoie "ailleurs" pour indiquer à ce à quoi tu le renvoie qu'il y a un nouvel utilisateur.

    Je te conseille d'avoir un objet qui s'occupe de l'ensemble de la gestion des utilisateurs connectés (ce sera déjà une responsabilité suffisante ):
    il crée un utilisateur lorsque la connexion a été acceptée par le serveur
    il détruit l'utilisateur lorsque celui-ci veut se déconnecter
    entre les deux, il garde en mémoire l'utilisateur connecté, et permet d'obtenir les services que l'on attend de ce dernier ("rappelle moi le nom", "peut-il faire ceci ou cela", "quel est son rang",...)
    Donc voilà selon le rang dans MySql je créer une instance d'utilisateur, d'opérateur ou d'administrateur dans mainwindow et je l'envoie à dialog.
    Bon après c'est un peu du bricolage d'avoir une variable Rang, juste parce que je n'arrive pas à dire "si le pointeur utilisateur est un operateur".
    Justement, et c'est en cela que l'héritage est intéressant:

    L'héritage permet ce que l'on appelle le polymorphisme, c'est à dire l'adaptation d'un comportement commun aux différents types qui dérivent d'un type commun (par exemple le fait de répondre à "quel est ton rang") au type dynamique utilisé.

    Pour cela, il "suffit" de déclarer la fonction relative au comportement comme virtuelle et de redéfinir le comportement de cette dernière pour les classes dérivées pour lesquelles le comportement d'origine n'est pas adapté.

    Un petit tour du coté de la partie de la FAQ dédiée à l'héritagete permettra de comprendre ce que j'essaye d'expliquer
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  15. #15
    Membre extrêmement actif
    Avatar de Ryu2000
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2008
    Messages
    9 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2008
    Messages : 9 604
    Points : 18 520
    Points
    18 520
    Par défaut
    Ok merci, je vais voir ce que je peux améliorer.
    Keith Flint 1969 - 2019

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

Discussions similaires

  1. Utilisation de classes utilisateur en IDL
    Par tdudouet dans le forum CORBA
    Réponses: 3
    Dernier message: 21/10/2008, 10h04
  2. pointeur sur une classe utilisateur
    Par maa dans le forum C#
    Réponses: 15
    Dernier message: 06/07/2007, 16h25
  3. Classe Utilisateur et UML
    Par SOXI dans le forum UML
    Réponses: 1
    Dernier message: 31/12/2006, 18h18
  4. Réponses: 2
    Dernier message: 14/11/2006, 15h59
  5. Class template hérité
    Par Azharis dans le forum Langage
    Réponses: 4
    Dernier message: 24/06/2005, 22h03

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