La méthode MVC

Eléphant du PHP | 145 Messages

09 févr. 2012, 12:57

Bonjour,

Il y a quelques temps, je me suis dis : "Tiens, je vais essayer de changer mes habitudes et respecter un standard au niveau de l'architecture de mes fichiers WEB".

Comme vous l'avez compris en lisant le titre, je me suis donc penché très sérieusement sur la méthode "Modèle Vue Controler" (MVC) et j'ai lu des dizaines de pages sur divers sites explicatif.

C'est avec conviction que je tente d'utiliser cette méthode pour les sites que je développe mais faut dire que parfois, je me retrouve avec des éléments entre les mains et je ne sais vraiment pas quoi en foutre.

Donc si je résume bien :
-Le Contrôleur et le lien direct avec le client, il va chercher ce qu'il affiche dans la vue et récolte les données dans le modèle
-Le Modèle se connecte à la base de données et effectue la plupart des contrôles sur les variables
-La Vue gère les éléments à afficher et peux parfois récupérer les données sur le Modèle

Bon jusque là, on peut dire que ça va.

En ce qui concerne mes librairies, j'ajoute un dossier Libs à la racine, un dossier external dans celui-ci.
En gros, ça me donne ça :
-index.php
  • ->Controleur
    ->Global
    ->images
    ->langue
    ->libs
    • ->external
    ->Modèle
    • ->Ajax
      ->Classe
    ->Vue
    ->Defaut
    • ->css
      ->form
    ->template2
    ->template3
Bon, je met Ajax dans le modèle, mais est-ce vraiment sa place?
Pour le JS, je le met principalement dans libs, est-ce le mieux?
En faite, en ce qui concerne le classique MVC, je pense que je contrôle, mais je me retrouve vraiment dubitatif en ce qui concerne tous les autres éléments.

Et vous, comment faites vous?

Cordialement,
Albat90 ;)
La culture, c'est comme la confiture, moins on en a, plus on l'étale.

Eléphant du PHP | 209 Messages

09 févr. 2012, 13:52

Salut,

Tu as bien résumé. Reste à voir la pratique :p

Il faut faire attention à ne pas faire du BVC (B pour Bordel). Le Modèle peut-être également sous-découpé (PPO, Mappers, DAO par exemple). Le MVC répond à une problématique de responsabilités mais il ne faut pas oublier à continuer de découper cela si besoin afin d'améliorer la flexibilité de ton application. Cela est plus automatique pour la vue que l'on va découper avec un layout principal suivi de bloc mais il faut en faire de même pour le modèle.

Concernant ton architecture, je te conseille de créer un dossier resources (enfin tu l'appelles comme tu veux :D) dans lequel tu auras tes images, js, css, vidéos, sons et autres contenus. Cela te permettra de configurer un point d'entrée unique à ton application et de proposer un accès direct à tes ressources un peu sur le principe de ZF.
Bon, je met Ajax dans le modèle, mais est-ce vraiment sa place?
En fait, l'AJAX ne change absolument rien au fonctionnement du MVC. C'est une nouvelle requête HTTP sur le serveur qui contiendra une réponse dans un format HTML, XML, JSON ou autre. Seul l'affichage de tes données changera mais le fonctionnement interne est exactement le même. Ton contrôleur devra cependant faire une vérification supplémentaire pour valider que l'appel serveur a bien été effectué par XML Http Request.

Sinon, si tu travailles sur beaucoup de sites, je te conseille quand même fortement d'utiliser un framework MVC. Tu en as des plus ou moins light mais une fois le framework maîtrisé, tu gagneras en temps de développement, en performance et surtout en sécurité.

++

Eléphant du PHP | 145 Messages

09 févr. 2012, 16:37

Salut,

Merci de ta réponse.
Je comprends que le découpage est bon dans un sens, mais n'est-il pas trop gênant pour les include lorsqu'il s'agit d'appeler les pages s'y trouvant?

Disons que l'on peut stocker certains chemins classiques dans des constantes comme l'adresse du serveur, le chemin vers controleur, le chemin vers la classe de BDD... Mais finalement, il en restera toujours un morceau à personnaliser ^_^

En ce qui concerne Ajax, je vois ce que tu veux dire au niveau des appels. En gros, voici le chemin que réalise mon site pour afficher une page.

index.php --> Controleur/page1.php --> Modèle/page1.php --> Controleur/page1.php --> Vue/page1.php --> Controleur/page1.php --> index.php (Affichage)

maintenant pour un appel Ajax, je suis obligé de passer par index.php. En effet, car pour plus de sécurité, j'ai mis en place dans mon fichier .htaccess une restriction d'accès au fichier PHP que par index .php

Code : Tout sélectionner

#Interdit tout visibilité ou execution de .php sauf par php lui même <Files *.php> Order deny,allow Deny from all </Files> #Autorise le fichier index.php à être appeler directement en dehors de tous scripts <Files index.php > Order deny,allow Allow from 127.0.0.1 Deny from all </Files>
Mon fichier index, lui, include automatiquement le header et le footer
<?php

// Initialisation
include 'global/init.php';

// Début de la tamporisation de sortie
ob_start();

// Si un module est specifié, on regarde s'il existe
if (!empty($_GET['opt'])) {

	$opt = htmlspecialchars($_GET['opt']);
// Load sections
	switch( $opt ) {
		// Case Index
			
		case URL_CONNEXION :
			include_once(ROOT . CONTROLEUR . 'connexion.php');
			break;
			
		case URL_DEPOT :
			include_once(ROOT . CONTROLEUR . 'depot.php');
			break;
			
		case URL_INSCRIPTION :
			include_once(ROOT . CONTROLEUR . 'inscription.php');
			break;
			
		case URL_RECHERCHE :
			include_once(ROOT . CONTROLEUR . 'recherche.php');
			break;
			
		default :
			header('Location: '.URL_SITE);
			break;
	}
}
else{
	include_once(ROOT . CONTROLEUR . 'accueil.php');
}

// Fin de la tamporisation de sortie
$contenu = ob_get_clean();

// Début du code HTML
include 'global/header.php';


echo $contenu;

// Fin du code HTML
include 'global/footer.php';
?>
Donc si j'appel un fichier PHP AJAX au travers de mon index, je me retrouve automatiquement en résultat mon header et mon footer.
Pour essayer de contrer ceci, j'ai autoriser un autre fichier à appeler mes fichiers PHP soit controleur.php en ajoutant la règle dans le .htaccess.

Code : Tout sélectionner

#Autorise le fichier controleur.php à être appeler directement en dehors de tous scripts <Files controleur.php > Order deny,allow Allow from 127.0.0.1 Deny from all </Files>
Et donc, mon controleur.php permet d'afficher mes requêtes Ajax sans faire appel au header et footer.
<?php

// Initialisation
include 'global/init.php';

// Début de la tamporisation de sortie
ob_start();

// Si un module est specifié, on regarde s'il existe
if (!empty($_GET['val'])) {

	$opt = htmlspecialchars($_GET['val']);
// Load sections
	switch( $opt ) {
		// Case Index
		
		case 'inscription' :
			include_once(ROOT.MODELE.'ajax/ajax.inscription.php');
			break;
			
		default :
			header('Location: '.URL_SITE.'controleur.php');
			break;
	}
}
else{
	include_once(ROOT . CONTROLEUR . 'controleur.php');
}

// Fin de la tamporisation de sortie
$contenu = ob_get_clean();

echo $contenu;

?>
Bon, controleur.php connait les chemins puisque je les renseignes à la main, donc l'emplacement de mes fichiers PHP Ajax n'a plus d'importance, mais en faisant un test et en indiquant l'adresse URL de controleur.php avec la bonne variable $_GET, il m'affiche dans le navigateur le résultat, ce qui me semble assez dangereux pour la sécurité.

Donc j'en viens très rapidement à ton post qui me dit :
Ton contrôleur devra cependant faire une vérification supplémentaire pour valider que l'appel serveur a bien été effectué par XML Http Request.
Je ne pensais pas que c'était faisable, mais maintenant, je me rend compte que c'est super important, faut que je recherche quelques trucs là dessus, et si tu peux m'indiquer quelques pistes, je t'en serai très reconnaissant :P

Donc, au final, pour l'appel en Ajax, voici le chemin parcouru par le serveur :
index.php --> libs/ajax/script.js --> controleur.php --> modele/ajax/page_ajax1.php --> controleur.php --> libs/ajax/script.js --> index.php (affichage/modif)

Dans un sens, c'est quand même assez compliquer à comprendre, dans un autre, il y a un petit sentiment de sécurité, mais autre part, on a un gros sentiment de foutoir pas possible qui pourrait bien ralentir le serveur en cas de flux élevé.

Qu'en penses-tu?

Cordialement,
Albat90 ;)
La culture, c'est comme la confiture, moins on en a, plus on l'étale.

Eléphant du PHP | 209 Messages

09 févr. 2012, 17:47

Je comprends que le découpage est bon dans un sens, mais n'est-il pas trop gênant pour les include lorsqu'il s'agit d'appeler les pages s'y trouvant?
Non pas plus que d'appeler le MVC maintenant mon exemple est fait pour de l'objet.
Pour faire une aparté là-dessus, tu peux très bien imaginer un fonctionnement de cette manière : Contrôleur -> DAO -> Mapper -> PPO pour obtenir un objet de la base au niveau de ton contrôleur. Chaque "couche" s'occupe de son boulot : le DAO récupère les objets en base, le mapper transforme en objet PPO et le PPO te permet de manier tes données dans le contrôleur et dans la vue et pourquoi pas ailleurs (couche Service par exemple..).
Ton architecture est plus complexe mais au final, tu sais directement d'où vient le problème (s'il y en a :roll:), où effectuer des modifications en cas d'évolution du système (changement de SGBD par exemple) et tu n'as pas des classes immenses avec des objets divins qui savent tout faire.
Disons que l'on peut stocker certains chemins classiques dans des constantes comme l'adresse du serveur, le chemin vers contrôleur, le chemin vers la classe de BDD... Mais finalement, il en restera toujours un morceau à personnaliser ^_^
Oui bien sûr qu'il en restera un morceau à personnaliser mais le but est de faciliter et d'automatiser tout ce processus. Il ne s'agit pas non plus de tout stocker dans des constantes mais d'éviter de réécrire à chaque fois le même bout d'URL ceci pour améliorer la maintenabilité de ton code.
En ce qui concerne Ajax, je vois ce que tu veux dire au niveau des appels. En gros, voici le chemin que réalise mon site pour afficher une page.
index.php --> Controleur/page1.php --> Modèle/page1.php --> Controleur/page1.php --> Vue/page1.php --> Controleur/page1.php --> index.php (Affichage)

...

Mon fichier index, lui, include automatiquement le header et le footer
Pour moi (et ça ne regarde que moi ^^), tu as un problème d'architecture ici. Comment se fait-il que l'index fasse l'affichage ?! On a pourtant dit que c'était le travail de la vue :p

index.php --> Contrôleur/page1.php --> Modèle/page1.php -->* Contrôleur/page1.php --> Vue/page1.php
Le -->* signifie qu'il n'y a pas d'appel, c'est juste la fin de l'exécution de la page1.php du modèle qui fait s'exécuter la suite du contrôleur.

index.php : sert de point d'entrée et de bootstrap. En clair, il va initialiser ta session, tes objets (si tu en utilises) que tu peux utiliser partout dans ton application (le caching, la log par exemple) ou appeler tes classes utilitaires. Il va avoir un rôle de sécurisation également. Il appelle le contrôleur dont tu as besoin.
Contrôleur : Il appelle le modèle pour effectuer les traitements que tu désires et il va appeler ta vue.
Modèle : Il va effectuer tout le code métier : appel de WebServices, relation avec la BDD, ...
Vue : Elle récupère les données du modèle qui lui sont envoyés par le contrôleur. Elle les affiche et gère leur mise en page (inclusion css, js, images... ).

Si tu as des parties génériques (ce qui est souvent le cas), tu peux aussi découper ta vue en 2 parties : un layout et un/des bloc(s).
Le layout s'occupe d'afficher les blocs génériques (bannière, menu, pied de page, etc.), d'appeler les CSS, les JS, les métas et tout le tralala d'une page web. Et il va appeler également ton bloc "dynamique" propre à ce que ton contrôleur a renvoyé.

Comme ça :
- ton index reste ton point d'entrée.
- ton contrôleur se charge d'appeler les traitements et d'appeler l'affichage. Il gère le cas d'une requête Ajax et appelle le layout ou non en conséquence.
- ton modèle gère la relation avec la base.
- ta vue est découpée en layout et blocs. Le layout représente ton interface générale, chaque bloc vient se greffer à l'endroit voulu. Dans le cas d'ajax, le bloc sera du json par exemple et le layout ne sera pas appelé.

Au final et dans le cas le plus compliqué, tu as :
index.php --> controller/page1.php --> models/page1.php -->* vues/layout.php --> vues/page1.php
Et pour une requête Ajax :
index.php --> controller/page2.php --> models/page2.php -->* vues/page2.php
Je ne pensais pas que c'était faisable, mais maintenant, je me rend compte que c'est super important, faut que je recherche quelques trucs là dessus, et si tu peux m'indiquer quelques pistes, je t'en serai très reconnaissant :P
J'ai trouvé ça sur un site, ça doit fonctionner :
if (array_key_exists('HTTP_X_REQUESTED_WITH', $_SERVER) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
    // Traitement pour une réponse Ajax
}
J'espère avoir répondu à tes questions et désolé si je parle un peu trop d'objets (en dehors de ma dérive en haut), j'ai essayé de faire attention dans mes explications mais bon s'pas gagné :D

Eléphant du PHP | 145 Messages

09 févr. 2012, 18:13

Salut,

Merci pour ta réponse très instructive. Tu as tout à fais raison de partir sur de l'objet dans ce topic car c'est ce que j'utilise aussi :)
Au final et dans le cas le plus compliqué, tu as :
index.php --> controller/page1.php --> models/page1.php -->* vues/layout.php --> vues/page1.php
Et pour une requête Ajax :
index.php --> controller/page2.php --> models/page2.php -->* vues/page2.php
Oui je vois très bien ce que tu veux dire, en effet, les * que tu as placé sont aussi valable dans mon architecture. le modèle, lui, ne fait aucun appel aux autres dossier.

Par contre, en ce qui concerne les echo pour afficher le visuel, je le fait dans le contrôleur. En fait, mon contrôleur va simplement afficher des fonctions, se trouvant dans la vue, qui retourne le code à afficher.

Bon, s'il faut que je modifie cette partie, ce ne sera pas un problème, j'ai juste à remplacer les return $code; par echo $code.

Par contre, j'ai une petite question en ce qui concerne la vérification xmlhttprequest ; Penses-tu qu'a l'aide d'une autre page, il est possible de faire un appel ajax sur ma page php? Si oui, je devrais alors ajouter une condition qui demande si la demande s'effectue bien depuis ma page JS... Ou alors faire passer une variable générée par un salt+time sur les 3 dernières minutes (temps de validité du formulaire).

Enfin bon, merci beaucoup :)
La culture, c'est comme la confiture, moins on en a, plus on l'étale.

Eléphant du PHP | 209 Messages

09 févr. 2012, 18:23

Par contre, j'ai une petite question en ce qui concerne la vérification xmlhttprequest ; Penses-tu qu'a l'aide d'une autre page, il est possible de faire un appel ajax sur ma page php? Si oui, je devrais alors ajouter une condition qui demande si la demande s'effectue bien depuis ma page JS... Ou alors faire passer une variable générée par un salt+time sur les 3 dernières minutes (temps de validité du formulaire).
Oui il faut également que tu protèges cet accès. Le $_SERVER['REMOTE_ADDR'] devrait être suffisant pour ça je pense.

Si tu codes en objet et que tu n'as pas de gros besoins de performances, je te conseille fortement d'utiliser ZF ou Symfony pour faire du MVC. Tu éviteras de te galérer (même si ça fait du bien), tu auras d'autres idées d'architectures en tête (les deux ne fonctionnent pas du tout pareil) et surtout ton application sera bien plus sécurisée (sans remettre en cause tes connaissances, la taille de la communauté permet de tester un maximum de choses).
Et ça ne sert pas forcément à quelque chose de réinventer la roue si on n'en n'a pas l'utilité :D

Eléphant du PHP | 145 Messages

09 févr. 2012, 19:13

Merci beaucoup,

Je vais regarder ces petits framework de plus près :)

Si quelqu'un à des petits conseils concernant la méthode MVC et le système de Gestion, alors je suis preneur ^^

Cordialement,
Albat90 ;)
La culture, c'est comme la confiture, moins on en a, plus on l'étale.