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 :

architecture MVC - précisions


Sujet :

Langage PHP

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Février 2009
    Messages
    171
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2009
    Messages : 171
    Points : 78
    Points
    78
    Par défaut architecture MVC - précisions
    Bonjour,

    j'ai suivi le tuto suivant de Baptiste Pesquet : http://bpesquet.developpez.com/tutor...hitecture-mvc/

    Je me suis arrêté avant la construction du mini Framework, car la structure du site me suffisait amplement sans devoir passer par le Framework.

    Mais j'ai besoin de quelques précisions concernant l'architecture.

    la première :

    Est-il possible que pour certains contrôleurs, qu'aucun Modèle ne soit défini, par exemple pour la page d'accueil où le contenu n'est pas forcément dynamique?
    (Pour le moment je crée mes modèles pour tous mes contrôleurs, mais ils sont vides.)

    la deuxième :

    j'ai créé une section inscription sur le site, j'appelle donc mon contrôleur Inscription qui affiche le formulaire. Lorsque l'utilisateur valide le formulaire, le formulaire est envoyé au Routeur principal.
    Le routeur principal appelle de nouveau le contrôleur Inscription qui fait l'insertion dans la DB via une fonction, et le routeur principal appelle ensuite un controleur Information qui affiche une information à l'utilisateur.

    le code =>
    controleurInscription.php
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    <?php
     
    require_once 'Modele/Inscription.php';
    require_once 'Vue/Vue.php';
     
    class ControleurInscription
    {
    	private $inscription;
     
    	public function __construct()
    	{
    		$this->inscription = new Inscription();
    	}
     
    	public function inscription()
    	{
    		$vue = new Vue("Inscription");
    		$vue->generer(null);
    	}
     
    	public function inscrire($nom,$prenom,$pseudo,$mdp,$mail,$datenaissance,$question,$reponse)
    	{
    		$this->inscription->ajouterMembre($nom,$prenom,$pseudo,$mdp,$mail,$datenaissance,$question,$reponse);
    	}
    }
    le modèle Inscription :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    <?php 
     
    require_once 'Modele/Modele.php';
     
    class Inscription extends Modele
    {
    	public function ajouterMembre($nom,$prenom,$pseudo,$mdp,$mail,$datenaissance,$question,$reponse)
    	{
    		$sql = 'insert into membres (nom,prenom,pseudo,mdp,mail,datenaissance,question,reponse,date) values(?,?,?,?,?,?,?,?,?)';
    		$date = date('d/m/Y');
    		$this->executerRequete($sql,array($nom,$prenom,$pseudo,$mdp,$mail,$datenaissance,$question,$reponse,$date));
    	}
    }
    la vue Inscription
    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
     
    <?php 
    $this->titre="Palette Leuzoise - Inscription";
    $this->entete="Inscription";
    $this->idpage="inscription";
    ?>
     
    <form id="formInscription" onsubmit="return validationInscription();" action="accueil" method="post">
    	<label>Nom : <input type="text" name="nom" required /></label>
    	<label>Prénom : <input type="text" name="prenom" required /></label>
    	<label>Pseudo :<input type="text" name="pseudo" required /></label>
    	<label>Mot de passe :<input type="password" name="password1" id="password1" required /></label>
    	<label>Confirmation mot de passe :<input type="password" name="password2" id="password2" required /></label>
    	<label>Adresse e-mail :<input type="email" name="mail1" id="email1" required /></label>
    	<label>Confirmation adresse e-mail :<input type="email" name="mail2" id="email2" required /></label>
    	<label>Date de naissance :<input type="date" name="datenaissance" required /></label>
    	<label>Question :<input type="text" name="question" required /></label>
    	<label>Réponse :<input type="text" name="reponse" required /></label>
    	<div class="g-recaptcha" data-sitekey="xxx"></div>
    	<input type="submit" name="btInscription" value="M'inscrire" />
    </form>
    et enfin le routeur
    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
     
     
    	public function routerRequete()
    	{
    		try
    		{
    			if(isset($_GET['action']))
    			{
    				$this->action = $_GET['action'];
     
    				if($this->action == 'accueil')
    				{
    					if(isset($_POST['btInscription']))
    					{
    						$nom = $this->getParametres($_POST,'nom');
    						$prenom = $this->getParametres($_POST,'prenom');
    						$pseudo = $this->getParametres($_POST,'pseudo');
    						$mdp = $this->hashMdp($this->getParametres($_POST,'password1'));
    						$mail = $this->getParametres($_POST,'mail1');
    						$datenaissance = $this->getParametres($_POST,'datenaissance');
    						$question = $this->getParametres($_POST,'question');
    						$reponse = $this->getParametres($_POST,'reponse');
    						$this->ctrlInscription->inscrire($nom,$prenom,$pseudo,$mdp,$mail,$datenaissance,$question,$reponse);
    						$this->ctrlInformation->information($typeInfo,$prenom,$mail);
    					}
    					else 
    					{
    						$this->ctrlAccueil->accueil();
    					}
    				}
    				else if($this->action == 'listedeforce')
    				{
    					$this->ctrlListeDeForce->listedeforce();
    				}
    				else if($this->action == 'calendrier')
    				{
    					$this->ctrlCalendrier->calendrier();
    				}
    				else if($this->action == 'entrainements')
    				{
    					$this->ctrlEntrainements->entrainements();
    				}
    				else if($this->action == 'leclub')
    				{
    					$this->ctrlLeClub->leclub();
    				}
    				else if($this->action == 'inscription')
    				{
    					$this->ctrlInscription->inscription();
    				}
    				else
    				{
    					throw new Exception("Action non valide " . $this->action . $_SERVER['REQUEST_URI']);
    				}
    			}
    			else
    			{
    				$this->ctrlAccueil->accueil();
    			}
    		}
    		catch(Exception $e)
    		{
    			$this->erreur($e->getMessage());
    		}
    	}
    j'ai besoin de plusieurs précision.
    Tout d'abord, l'envoi du formulaire se fait vers action=accueil, ne serait-ce pas plus propre de l'envoyer vers action=inscription pour rester dans le même contexte? et là de tester l'existence de la variable $_POST?
    Ensuite lorsque l'inscription dans la DB est faire, j'appelle le controleur Information dans le routeur. est-il bien mis à cette endroit? ne faut-il pas le mettre dans le contrôleur Inscription dans la fonction d'insertion? ( ça me semble plus logique dans le Routeur, mais je ne suis pas sûr de l'endroit )

    Dernière question :

    Est-il possible qu'un contrôleur génère plusieurs vues ou sort-on, dans ce cas là, de l'architecture MVC?
    Je m'explique:
    J'ai mon contrôleur Information, qui servira à afficher des informations à l'utilisateur, par exemple pour lui dire que son compte a bien été créé ou par exemple qu'il ne peut pas se logguer car son compte n'a pas été activé, mais forcément la structure de la vue ne sera pas la même.
    Est-il préférable de créer dans ce cas là, plusieurs contrôleurs en fonction du type de message ou puis-je le faire avec un seul contrôleur?

    Merci pour les précisions que vous pourrez me donner.

  2. #2
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2008
    Messages
    1 576
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 1 576
    Points : 2 440
    Points
    2 440
    Par défaut
    Quelques réflexions:

    - évite d'utiliser le même identifiant pour une propriété et une fonction ($inscription/ inscription()). Un bon code est un code lisible, tu dois pouvoir lire le code rapidement et comprendre ce qu'il fait. en utilisant les mêmes identifiants, tu risques d'entraîner la confusion dans la lecture de ce que fait ton code.

    - À propos de ControleurInscription::inscrire():

    1. Il y a un principe de base en POO qui s'appele Single Responsibility Principle. Ça veut dire qu'une unité de code (module, classe, méthode, fonction) ne doit avoir qu'une seule responsabilité. Un contrôleur utilise des variables (données par un routeur ou un middleware) pour afficher une vue. Les méthodes publiques d'une méthode doivent donc toutes accomplir cette tâche. Personne ne doit pouvoir appeler une méthode d'un contrôleur sauf dans un seul cas: transmettre des variables afin d'afficher une vue. Toute méthode publique du contrôleur doit donc correspondre à une route. L'utilisation de inscrire() par routerRequete() est donc une erreur.

    2. inscrire() prends un certain nombre de paramètres qui n'existent pas dans la classe ControleurInscription. Il est donc clair que cette méthode ne doit pas faire partie de cette classe, puisque son lien avec cette classe est presque inexistante.

    3. Ton routeur est incompréhensible. Comment vas-tu faire pour déboguer une erreur dans cet enchêvetrement de if /else, qui va davantage s'agrandir quand tu vas ajouter encore des routes? De plus, tu testes isset($_GET['action'] et ensuite tu testes $_POST['btInscription'] pour savoir si la requête vient d'un formulaire. Tu ne peux pas mélanger deux méthodes HTTP.

    Pour répondre à tes questions:
    1. si ta page est complètement statique, tu n'as pas besoin de modèle. Un modèle "modélise" (représente) les données spécifiques à ton application. Ces données n'existent pas pour une page statique.

    2. Oui, envoie ton formulaire vers le même contrôleur qui l'a affiché, ou vers un contrôleur spécialisé dans le traitement du formulaire si ton cas est complexe. Et n'oublie pas la règle d'or: après une requete POST, on fait un traitement puis on fait une redirection GET. Comme ça le visiteur ne peut pas re-soumettre le même formulaire en faisant f5.

    3. Un routeur détermine les routes (çad quel contrôleur appeler en fonction de quel URL). Il ne doit même pas savoir quels objets tu manipules, et encore moins que tu les insères dans la base de données (Single Responsibility!!). L'insertion se fait dans la couche modèle, qui est appelée par un contrôleur.

    4. une route -> un contrôleur (sinon comment vas-tu faire?). Un contrôleur -> une responsabilité. Tout dépend donc de ce que fait ton contrôleur informations(). Un contrôleur peut très bien passer la main à différentes vues en fonction des circonstances, ex: une vue "succès", une vue "erreur attendue" et une vue "erreur inattendue", mais ne doit pas par exemple afficher 2 vues "succès" différentes.

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Février 2009
    Messages
    171
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2009
    Messages : 171
    Points : 78
    Points
    78
    Par défaut
    Merci de te pencher sur mon post.

    Pour ta première remarque, j'y consent, je m'y perd aussi de temps en temps Il faut que je perde cette mauvaise habitude.

    Par rapport au contrôleur Inscription :

    je commence par les questions les plus simples:
    1. Comment ne pas mélanger les méthodes post et get pour un formulaire? Je créé un champ hidden avec l'attribut name=action et value=inscription?
    Je devrais de toute façon tester d'abord $_GET['action'] et si n'existe pas le $_POST['action'] ?
    2. Comment rendre mon routeur plus compréhensible? penses-tu que je devrais continuer le tuto afin de créer le mini framework?
    3. Je suis perdu... que dois-je faire à la soumission de mon formulaire? je dois bien repasser par le routeur pour faire ma mise à jour? comment dire, dans le routeur, que le controleur inscription doit inscrire le membre?

    Merci.

  4. #4
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2008
    Messages
    1 576
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 1 576
    Points : 2 440
    Points
    2 440
    Par défaut
    1. Retire la vérification de $_POST du routeur, et envoie le formulaire directement dans ControleurInscription (voir 3)

    2. Oui, fais le mini-framework jusqu'au bout. C'est pensé pour te guider vers un objectif, ça n'a pas de sens de l'arrêter en cours de route. Dans l'idéal, un routeur ne devrait même pas connaître l'existence des contrôleurs et encore moins des vues. C'est toi qui doit lui passer le bon contrôleur lorsque tu définis une route. Le routeur du tutoriel va dans ce sens, mais pas complètement. Pense à un routeur comme une sorte d'array: quand tu crée une nouvelle route, tu lui donne un url et une méthode à exécuter pour cet url (qui est généralement un contrôleur, mais pas toujours). Ensuite, lorsqu'un visiteur navigue sur cet url, le routeur va chercher dans ses entrailles à quel méthode il doit exécuter, et l'exécute, sans même savoir ce que contient cette méthode ou à quoi il correspond.

    3. Tu envoies donc tous les urls action=inscription vers ControleurInscription. C'est ensuite à ce contrôleur de décider comment traiter la requête en fonction de la méthode, get ou post. Encore une fois, continue le tuto jusqu'au bout d'abord. Regarde comment il utilise la classe Requete pour faire passer les paramètres au lieu d'utiliser GET et POST. Une fois que tu as fini le tuto, si tu as des questions (ou si tu as des questions sur le tuto lui-même), reviens ici.

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Février 2009
    Messages
    171
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2009
    Messages : 171
    Points : 78
    Points
    78
    Par défaut
    Bonjour Tsilefy,

    Effectivement, en allant jusqu'au bout du tutoriel, j'ai eu réponse à toutes mes questions.

    Par contre, dans la solution proposée, même s'il traîte les GET et les POST séparement, l'envoi du formulaire semble bien utiliser les deux méthodes

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    <form method="post" action="billet/commenter">
        <input id="auteur" name="auteur" type="text" placeholder="Votre pseudo" 
               required /><br />
        <textarea id="txtCommentaire" name="contenu" rows="4" 
                  placeholder="Votre commentaire" required></textarea><br />
        <input type="hidden" name="id" value="<?= $billet['id'] ?>" />
        <input type="submit" value="Commenter" />
    </form>
    Je laisse le poste ouvert le temps d'adapter complètement ce que j'ai mis en commentaire de ce que j'avais déjà fait.

    Bonne soirée.

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Février 2009
    Messages
    171
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2009
    Messages : 171
    Points : 78
    Points
    78
    Par défaut
    Et bien je suis déjà bloqué

    Voici mon constructeur Inscription

    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
     
    <?php
     
    require_once 'Framework/Controleur.php';
    require_once 'Modele/Inscription.php';
     
    class ControleurInscription extends Controleur
    {
    	private $inscription;
     
    	public function __construct()
    	{
    		$this->inscription = new Inscription();
    	}
     
    	public function index()
    	{
    		$this->genererVue(null);
    	}
     
    	public function inscrire()
    	{
    		$nom = $this->requete->getParametre("nom");
    		$prenom = $this->requete->getParametre("prenom");
    		$pseudo = $this->requete->getParametre("pseudo");
    		$mdp = $this->requete->getParametre("password1");
    		$mail = $this->requete->getParametre("mail1");
    		$datenaissance = $this->requete->getParametre("datenaissance");
    		$question = $this->requete->getParametre("question");
    		$reponse = $this->requete->getParametre("reponse");
     
    		$this->inscription->ajouterMembre($nom,$prenom,$pseudo,$mdp,$mail,$datenaissance,$question,$reponse);
     
    	}
    }

    Jusque là tout va bien, le membre est bien créé dans ma DB mais... j'arrive sur une page blanche car je ne rappelle pas l'action "index" de ce constructeur comme dans le tuto.
    Pourquoi? parce que je veux appeler un autre constructeur (InformationInscription) qui n'est pas connu par ce constructeur Inscription.

    Comment faire?
    De plus je dois fournir des données récupérées via les paramètres dans le constructeur Inscription pour les passer au constructeur InformationInscription.

    Une idée?

    Merci

  7. #7
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2008
    Messages
    1 576
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 1 576
    Points : 2 440
    Points
    2 440
    Par défaut
    Quand tu es dans un contrôleur et que tu veux passer la main à un autre contrôleur, il faut faire une redirection vers l'URL de ce contrôleur, en passant les paramètres dans l'URL.
    Ex:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    header("Location: http://www.monsite.dev?action=InformationInscription&typeinfo=typeinfo&prenom=prenom&email=mail");
    Bien évidemment, ton routeur doit router l'action InformationInscription vers le contrôleur InformationInscription, et dans ce dernier, ta méthode information() doit recevoir la valeur de typeinfo, prenom & email (probablement à travers un objet Requête).

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Février 2009
    Messages
    171
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2009
    Messages : 171
    Points : 78
    Points
    78
    Par défaut
    en suivant ta remarque, 1 controleur = 1 vue, le paramètre typeinfo ne semble plus utile!?

    par contre, j'aimerai bien que ces données ne se voient pas dans l'url.
    est-ce qu'utiliser des variables de sessions semble judicieux?

    Merci

  9. #9
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2008
    Messages
    1 576
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 1 576
    Points : 2 440
    Points
    2 440
    Par défaut
    Tu peux utiliser les sessions, mais comme ce sont des variables à usage unique, je te conseille de les supprimer tout de suite après leur utilisation (pour ne pas avoir des effets secondaires imprévisibles plus tard).

  10. #10
    Membre régulier
    Profil pro
    Inscrit en
    Février 2009
    Messages
    171
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2009
    Messages : 171
    Points : 78
    Points
    78
    Par défaut
    J'aurais juste une dernière question point de vue organisation.

    J'ai besoin d'avoir une fonction envoiMail mais enverra des mails différents en fonction du message à envoyer. Par exemple un mail de confirmation lorsqu'un utilisateur s'inscrit.
    Hors architecture MVC, la première chose qui vient en tête c'est une classe...

    Comment bien faire les choses pour rester dans le contexte MVC?

    Merci

  11. #11
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2008
    Messages
    1 576
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 1 576
    Points : 2 440
    Points
    2 440
    Par défaut
    Le MVC est un pattern d'interface utilisateur, et pas (contrairement à ce que beaucoup de débutants croient), un pattern d'organisation de toute l'application. Tu es donc autorisé (voire encouragé) à utiliser d'autres classes qui ne font pas partie de tes M, V et C. Ces classes ont même un nom: "services".

    Puisque c'est juste pour apprendre, crée une classe pour l'email (si c'est pour un vrai site, il faut utiliser une bibliothèque existante comme swiftmailer ou phpmailer et non inventer sa propre classe), utilise-la dans ton contrôleur:
    - tu crées une classe Mail
    - tu crée dans ton contrôleur une méthode protected envoiMail($params) qui prend en paramètres les valeurs nécessaires pour l'email (destinataire, expéditeur, message, pièces jointes, etc...) et qui crée et envoie l'email
    - tu appelle la méthode envoiMail() depuis les méthodes publiques de ton contrôleur, à chaque fois que c'est nécessaire.

    Puis, si tu découvres que tu as besoin de cette méthode envoiMail dans plusieurs classes de contrôleur, tu crée une classe de base Controleur, avec une seule méthode: envoiMail, et ensuite tu fais hériter tes controleurs de cette classe de base.

    Plus tard, lorsque tu auras progressé, tu découvriras qu'il y a de meilleurs moyens pour organiser les services, mais pour l'instant fais comme ça.

  12. #12
    Membre régulier
    Profil pro
    Inscrit en
    Février 2009
    Messages
    171
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2009
    Messages : 171
    Points : 78
    Points
    78
    Par défaut
    Un tout tout grand merci en tout cas pour m'avoir aiguillé.

    Je vais commencer par une classe que je ferais par moi-même.

    Maintenant pour apprendre il me faut des sources, est-ce que tu as des sources concernant ces "services"? mes recherches Google ne me conduisent à rien.

    Merci

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

Discussions similaires

  1. architecture mvc etxml/xsl
    Par kiko2005 dans le forum XSL/XSLT/XPATH
    Réponses: 6
    Dernier message: 14/08/2009, 15h52
  2. Architecture MVC & C++ Builder ?
    Par zi_omnislasher dans le forum C++Builder
    Réponses: 5
    Dernier message: 15/12/2006, 00h24
  3. Utiliser une architecture MVC
    Par misterniark dans le forum MVC
    Réponses: 5
    Dernier message: 03/11/2006, 23h35
  4. [Spring MVC] Architecture MVC dans spring
    Par Alec6 dans le forum Spring Web
    Réponses: 4
    Dernier message: 11/10/2006, 13h35
  5. Architecture MVC
    Par Bobleponge dans le forum Servlets/JSP
    Réponses: 7
    Dernier message: 20/06/2005, 11h16

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