web-dev-qa-db-fra.com

Comprendre les vues MVC dans PHP

Il me semble difficile de comprendre le concept de vues dans MVC. C’est ce que j’ai lu, la couche qui gère la présentation dans l’application, mais la plupart des documents que j’ai lus semblent être différents à question dans celui-ci de PHP Master.com .

View est une classe avec des fonctions qui renvoient du code HTML. Où se trouve le reste de mon code HTML? Devrait-il être placé dans des pages .html indépendantes qui accèdent à ce code View?

Dans cet article, tiré de php-html.net , la vue est un simple fichier HTML portant l’extension .php, mais comment accèdent-ils à ces données? Je ne vois pas require() ou quoi que ce soit qui ressemble aux instanciations du premier tutoriel.

31
Eddnav

Remarque: les modèles inspirés de MVC et MVC sont des constructions avancées. Ils sont destinés à être utilisés dans des bases de code où le code ordinaire orienté objet (qui suit SOLID et d’autres directives) commence à devenir ingérable. En introduisant ce modèle, vous imposeriez des contraintes supplémentaires, ce qui vous permettrait ensuite de contenir des applications très complexes. MVC est not destiné aux applications "hello world".


Commençons par le début ...

L'idée de base des modèles de conception inspirés par MVC et inspirés par MVC est la suivante: Separation of Concerns . Cette séparation est double:

  • la couche de modèle est distincte de la couche d'interface utilisateur: 
  • les vues sont séparées des contrôleurs

enter image description here

La couche modèle (et non "classe" ou "objet") contiendrait plusieurs groupes de structures, chacune traitant d'un aspect différent de la logique métier. Les principales parties seraient: 

  • objets de domaine : validation, règles de gestion
  • abstraction de stockage: persistance et mise en cache des données d'objets de domaine
  • services: logique d'application

En outre, il pourrait y avoir un mélange de référentiels , unités de travail et autres.

La couche UI se compose principalement de vues et de contrôleurs. Mais ils utilisent tous deux des services pour interagir avec la couche modèle. Les services permettent aux contrôleurs de modifier l'état de la couche de modèle et aux vues de collecter des informations en fonction de ce nouvel état.

Dans le contexte Web, les vues et les contrôleurs forment une paire lâche, en raison de la nature demande-réponse présentée par les applications Web.

Il est à noter que, bien que les contrôleurs peuvent modifient directement l'état de la vue actuelle, il est plus courant que ces modifications soient effectuées via le modèle. L'une des raisons de modifier directement la vue est, par exemple, le moment où, au lieu de XML, vous devez répondre avec JSON. 

Bien que l'on puisse également soutenir que l'on pourrait simplement instancier une vue différente pour chaque format de sortie et tirer parti du polymorphisme.


Qu'est-ce qui n'est pas vue?

Il existe une idée fausse répandue selon laquelle les vues sont simplement des fichiers de modèle glorifiés. Cette erreur est devenue extrêmement populaire après la publication du framework de prototypage RubyOnRails.

Les vues ne sont pas des modèles. Si vous les utilisez en tant que tels, vous rompez le principe de base des modèles inspirés de MVC et de MVC.

Si vous prétendez que les modèles sont des vues, cela aura un impact énorme sur votre architecture. Il n'y a pas de place pour la logique de présentation dans la vue, vous devez donc pousser la logique de présentation dans la couche contrôleur ou dans la couche modèle. Le choix habituel est "contrôleur", car la plupart des gens comprennent que la logique de présentation n'a pas sa place dans la couche modèle.

Cela provoque essentiellement une fusion de vues et de contrôleurs. 


Que fait la vue?

La responsabilité de la vue est de traiter de la logique de présentation. Dans le contexte du Web, l’objectif de view est de produire une réponse à l’utilisateur (qui, d'ailleurs, est le navigateur, pas l'humain)}. 

Techniquement, il serait possible de créer des vues côté client, ces sockets Web utilisateur pour observer la couche de modèle, mais dans la pratique, il est pratiquement impossible de les implémenter. Surtout pas dans PHP - environnement.

Pour créer cette réponse, la vue acquiert les informations de la couche modèle et, en fonction des données collectées, assemble les réponses en distribuant les données aux modèles et en effectuant le rendu ou, parfois, en envoyant simplement un en-tête d'emplacement HTTP.

Lorsque vous utilisez Post/Redirect/Get , la partie de redirection est effectuée par la vue, et non par le contrôleur, comme le font souvent les gens.


Bit hautement subjectif:

Dernièrement, j'ai préféré interagir avec MVC en utilisant l'approche suivante:

  // the factory for services was injected in constructors
  $controller->{ $method.$command }($request);
  $view->{ $command }();
  $view->respond();

Le $method est le REQUEST_METHOD actuel, qui a été ajusté, simule une API de type REST, et le $command est ce que les gens appellent habituellement "action". Le contrôleur dispose de routines distinctes pour les demandes GET et POST (un autre). Cela permet d'éviter d'avoir la même if dans chaque "action". 

Sur la vue, j'appelle deux méthodes. Le premier est un appel dynamique pour rassembler les données. Et la seconde vise à créer un type de réponse.

Warning: je suspecte que cette configuration contienne une violation SRP . L'adopter comme votre propre pourrait être une mauvaise idée.


Qu'en est-il de DRY?

Comme vous l'avez peut-être déjà remarqué, le fait d'avoir des vues en tant qu'instances présente un léger problème. Vous vous retrouveriez avec des morceaux de code répétés. Par exemple: menu ou pagination. 

Regardons la pagination. La pagination contient une logique, mais cette logique n'est pas liée à la couche de modèle. Le modèle n'a pas de concept de "page". Au lieu de cela, ce bit de logique réside dans la couche d'interface utilisateur. Mais si chacun de vos points de vue contient ou hérite de la pagination, il s'agirait alors d'une violation flagrante du PRS (et de plusieurs autres principes également).

Pour éviter ce problème, vous pouvez (et devriez, IMHO) introduire objets de présentation dans vos vues. 

Remarque: bien que Fowler les appelle "modèles de présentation", je pense que ce nom ajoute simplement à la confusion qui règne à propos du modèle. Par conséquent, je recommanderais de les appeler "objets de présentation" à la place.Les objets de présentation traitent de morceaux de logique répétés. Cela rend les vues beaucoup "plus légères", et dans certains aspects commence à refléter la structure des services de la couche modèle.

L'interaction entre les objets de présentation et templates devient similaire à l'interaction entre les objets de domaine et les mappeurs de données

.


N ° Cette approche spécifique est fortement axée sur le code, où la couche d'interface utilisateur est très complexe et il est nécessaire de séparer le traitement des entrées de la présentation pour une saine gestion.

Si votre application possède une interface utilisateur très simple, telle que .. emm .. vous créez REST - API pour un projet intégré plus grand. Dans un tel cas, l'option pragmatique peut consister simplement à fusionner chaque paire contrôleur-vue en une seule classe. 

Cela peut également être une bonne étape lors de la refactorisation d'une base de code héritée, car cette approche moins contrainte vous permet de déplacer des morceaux entiers de l'ancien code. Lorsque vous avez isolé ces éléments de code plus anciens et vérifié que tout fonctionne toujours (car le code hérité n’a jamais de tests .. c’est ainsi qu'il devient "hérité"), vous pouvez alors commencer à le diviser davantage, tout en vous concentrant sur la logique métier de l'interface utilisateur. 

.


P.S. I myself am still struggling with figuring out a way how best to deal with views. This post is less of an answer and more like a snapshot of my current understanding.

72
tereško

Le deuxième tutoriel est la façon dont fonctionne le framework Code Igniter, et celui auquel je suis habitué. Je le suis même sans utiliser de cadre.

En fait, le développeur doit mettre en pratique les principes de type MVC, sinon il peut fabriquer les lasagnes ou les spaghettis même en utilisant le cadre le plus orienté de type MVC.

En utilisant l’approche "fichier PHP en tant que modèle de vue", l’idéal serait d’utiliser des instructions minimales PHP, en principe uniquement pour les structures de répétition (foreach ($array as $item)), les conditions de base (if ($boolean)) et echo - comme si c’était en fait un modèle langue et rien de plus.

Ainsi, les balises <?php ?> dans les fichiers de modèle de vue doivent être simplement des espaces réservés et rien d'autre.

Aucune requête de base de données, accès au modèle, calculs, etc. ne doit être effectué dans le fichier de modèle de vue. En gros, il devrait être traité comme un fichier HTML avec des espaces réservés. (Avec ses CSS et JavaScript associés. Les choses peuvent devenir plus complexes lorsque l'application s'appuie beaucoup sur JavaScript/AJAX ...)

En suivant ces principes simples, nous séparons efficacement la présentation de la logique métier. Même si cela semble si simple, je suis fatigué de traiter avec le code Code Igniter qui ne le suit pas. Certains utilisent des "fonctions d'assistance" pour dissimuler les appels de modèle/base de données - et pensent que c'est une bonne pratique! :-)

Vous ne voyez pas require dans ces fichiers de gabarit de vue PHP car ils sont requis à la place, à partir des méthodes "view building".

Bien sûr, il ne faut pas echo et/ou print de l'intérieur du contrôleur et des fonctions de modèle. C’est aussi très simple, mais je suis aussi fatigué de voir le code spaghetti refléter le code HTML depuis les méthodes du contrôleur CI.

En pratique, le contrôleur appelle les méthodes du modèle, crée toutes les données nécessaires à la vue et, à la dernière étape, appelle la vue (c’est-à-dire le construit et l’affiche), en lui transmettant les données déjà obtenues.

Logique? Je ne sais pas si j'ai répondu à votre question. Au moins, ce sont mes "2 cents".

10
J. Bruni

Différents cadres utilisent une logique différente pour affecter des variables à afficher et à obtenir son contenu. Voici un exemple simple utilisant la fonction ob_start ().

<?php
     $title = 'Hello...';
     ob_start();
     file_get_contents('view.phtml');
     $viewContents = ob_get_clean();
     echo $viewContents;

?>

//view.phtml
<b>Hello the title is <?php echo $title; ?></b>

J'espère que cela répond à votre question ...

1
Jay Bhatt

Vous êtes censé transmettre à une méthode de la classe view tout ce dont elle a besoin pour créer une vue indépendante du format de sortie. La plupart des développeurs utilisent une sorte de moteur de modélisation pour créer le gros de la page, puis remplissent le corps avec des informations spécifiques à la demande. Il y a tellement de façons de s'y prendre. Il est également utile de disposer d'une classe de vues abstraites définissant des méthodes d'assistance pour les éléments communs tels que les formulaires et les entrées.

Cette couche est abstraite afin que la logique de votre application n'ait pas à changer si vous décidez de modifier le format de conception ou de sortie de quelque manière que ce soit.

Edit: Chaque module représenté par un ensemble MVC aurait son propre affichage qui a un ensemble de méthodes responsables de l’envoi de votre sortie au navigateur. Vous pouvez y aller de plusieurs façons, mais voici un exemple:

class testModule_view extends viewAbstract {
    public function showTestData($title, $subtitle, $data) {
        $XHTML = '<h1>' . $title . '</h1>'
            . '<h2>' . $subtitle . '</h2>'
            . parent::data2table($data);

        parent::outputToBrowser(DEFAULT_TEMPLATE, $XHTML);
    }
}

Ceci est juste un exemple rapide pour vous donner une idée de ce à quoi une méthode de vue simple pourrait ressembler.

1
km6zla
<?php

class View {

protected $data;

protected $path;

protected static function getDefaultViewPath() {
    $router = App::getRouter();

    if(!$router){
        return false;
    }

    $controller_path = $router->getController();
    $method_path = ($router->getMethodPrefix() !== "" ? $router->getMethodPrefix() . '_' : '') . $router->getAction();

    return ROOT . "/views/" . $controller_path . "/" . $method_path . ".phtml";
}

public function __construct($data = array(), $path = null) {

    if(!$path){
        //default
       $path = $this->getDefaultViewPath();
    }

    if(!file_exists($path)){
        throw new Exception("Error view file!");
    }

    $this->data = $data;
    $this->path = $path;
}


public function render(){
    $data = $this->data;

    ob_start();
    include ($this->path);
    $content = ob_get_clean();

    return $content;
}

}

0
David

Lorsque le navigateur appelle une page, un contrôleur est chargé pour celle-ci . Le contrôleur gère le cycle de vie de votre application . Il récupère les données du modèle, qui ne sert qu'à obtenir une base de données) . La vue n’est que du HTML, le contrôleur renvoie la vue et, si nécessaire, lui passe quelques paramètres.

0
hice3000

Vérifiez ce code: 

include_once(ROOT.'/'.'config/config.php');

function __autoload($class_name){
    $lib_path = ROOT . '/' . 'lib/class.'.$class_name . '.php';
    $controller_path = ROOT . '/' . 'controllers/'.str_replace("controller", "", strtolower($class_name)) . '.controller.php';
    $model_path = ROOT . '/' . 'models/'.strtolower($class_name) . '.php';

if(file_exists($lib_path)){
    require_once ($lib_path);
} else if (file_exists($controller_path)){
    require_once ($controller_path);
} else if(file_exists($model_path)){
    require_once ($model_path);
} else {
    throw new Exception("File {$class_name} cannot be found!");
}

}
0
David