Entendiendo las vistas MVC en PHP


Tengo que parecer problemas para entender el concepto de Vistas en MVC, son, según lo que he leído, la capa que gestiona la presentación en la aplicación, pero muchos de los materiales que he estado leyendo parecen ser diferentes en este asunto de PHP Master.com .

La vista es una clase con funciones que devuelven algún código HTML, ¿dónde está el resto de mi HTML? debe ser puesto en independiente .páginas html que acceden a este código de vista?

En este artículo, de php-html.net la vista es un simple archivo HTML con un .extensión php, pero ¿cómo están accediendo a esos datos? No veo require() ni nada parecido a las instancias en el primer tutorial.

Author: Matt Busche, 2013-05-16

7 answers

Nota: los patrones inspirados en MVC y MVC son construcciones avanzadas. Están destinados a ser utilizados en bases de código donde el código ordinario orientado a objetos (que sigue SÓLIDO y otras directrices) comienza a volverse inmanejable. Al introducir este patrón, impondría restricciones adicionales, lo que le permite contener aplicaciones muy complejas. MVC es no para aplicaciones de "hola mundo".


Comencemos desde principio ...

La idea central detrás de MVC y patrones de diseño inspirados en MVC es Separación de Preocupaciones. Dicha separación es doble:

  • la capa de modelo está separada de la capa de interfaz de usuario:
  • las vistas están separadas de los controladores

introduzca la descripción de la imagen aquí

La capa del modelo (no "clase" u "objeto") contendría varios grupos de estructuras, cada uno tratando como un aspecto diferente de la lógica de negocio. Las partes principales serían:

  • objetos de dominio : validación, reglas de negocio
  • abstracción de almacenamiento: persistencia y almacenamiento en caché de datos de objetos de dominio
  • servicios: lógica de la aplicación

También podría haber mezcla en los repositorios , unidades de trabajo y otras.

UI layer consiste principalmente en vistas y controladores. Pero ambos utilizan servicios para interactuar con la capa del modelo. Los servicios proporcionan el camino para que los controladores cambie el estado de la capa del modelo y que las vistas recopilen información en función de ese nuevo estado.

En el contexto de la web, las vistas y los controladores forman un par suelto, debido a la naturaleza solicitud-respuesta que exhiben las aplicaciones web.

Cabe señalar que aunque los controladores pueden alterar el estado de la vista actual directamente, es más común que estos cambios se efectúen a través del modelo. Una razón para alterar la vista directamente es, por ejemplo, cuando en su lugar de XML que necesita para responder con JSON.

Aunque también se podría argumentar que uno podría simplemente instanciar una vista diferente para cada formato de salida y aprovechar el polimorfismo.


¿Qué no es vista?

Existe una idea errónea generalizada de que las vistas son simplemente un archivo de plantilla glorificado. Este error se hizo extremadamente popular después del lanzamiento de RubyOnRails prototyping framework.

Las vistas no son plantillas. Si los usa como así, rompes el principio básico detrás de los patrones inspirados en MVC y MVC.

Si pretende que las plantillas son vistas, tiene un enorme impacto en su arquitectura. No hay lugar para la lógica de presentación en la vista, por lo tanto, puede empujar la lógica de presentación ya sea en el controlador o en la capa de modelo. La opción habitual es "controlador", porque la mayoría de la gente entiende que la lógica de presentación no tiene lugar en la capa del modelo.

Esencialmente, esto causa una fusión de puntos de vista y controladores.


¿Qué está haciendo view?

La responsabilidad de la vista es tratar con la lógica de presentación. En el contexto de la web, el objetivo de view es producir una respuesta al usuario (que, por cierto, es el navegador no el humano).

Técnicamente sería posible crear vistas del lado del cliente, ese usuario web sockets para observar la capa del modelo, pero en la práctica es prácticamente imposible de implementar. Especialmente no en PHP ambiente.

Para crear esta vista de respuesta adquiere información de la capa del modelo y, en función de los datos recopilados, ensambla la respuesta distribuyendo los datos a las plantillas y renderizando o, a veces, simplemente enviando un encabezado de ubicación HTTP.

Cuando se usa Post/Redirect/Get, la parte de redirección es realizada por la vista, no por el controlador como a menudo la gente tiende a hacer.


Altamente subjetivo bit :

Últimamente he preferido interactuar con MVC utilizando el siguiente enfoque:

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

El $method es el actual REQUEST_METHOD, que ha sido ajustado fake a REST-like API, y el $command es lo que la gente suele llamar "acción". El controlador tiene rutinas separadas para GET y POST (otro) peticiones. Esto ayuda a evitar tener el mismo if en cada "acción".

En la vista llamo a dos métodos. Primero es una llamada dinámica para recopilar los datos. Y segundo pretende crear algún tipo de respuesta.

Advertencia : Sospecho que esta configuración contiene una violación SRP. Adoptarlo como propio podría ser una mala idea.


¿Qué hay de DRY?

Como ya habrás notado, hay un pequeño problema con tener vistas como instancias. Terminarías repitiendo piezas de código. Por ejemplo: menú o paginación.

Veamos la paginación .. Paginación contiene lógica, pero esta lógica no está relacionada con la capa del modelo. El modelo no tiene concepto de "página". En su lugar, este bit de lógica residiría en la capa de interfaz de usuario. Pero si cada uno de sus puntos de vista contiene o hereda la paginación, entonces sería una clara violación de SRP (y en realidad varios otros principios también).

Para evitar este problema, puede (y debe, en mi humilde opinión) introducir objetos de presentación en sus vistas.

Nota: mientras Fowler los llama "modelos de presentación", creo que ese nombre solo se suma a toda la confusión de "qué es el modelo". Por lo tanto, recomendaría llamarlos "objetos de presentación" en su lugar.

Los objetos de presentación tratan con piezas repetidas de lógica. Esto hace que las vistas sean mucho más ligeras, y en algunos aspectos comienza a reflejar la estructura de los servicios de la capa del modelo.

La interacción entre los objetos de presentación y plantillas se vuelve similar a la interacción entre objetos de dominio y mapeadores de datos.


¿siempre necesito todo esto?

No. Este enfoque específico está muy orientado hacia el código, donde la capa de interfaz de usuario tiene mucha complejidad y necesita separar el manejo de la entrada de la presentación solo para sane sane.

Si su aplicación tiene una interfaz de usuario muy simple, como .. emm .. está haciendo REST API para un proyecto integrado más grande. En tal el pragmático la opción puede ser simplemente combinar cada par controlador-vista en una sola clase.

También puede ser un buen paso, al refactorizar una base de código heredada, porque este enfoque menos restringido le permite mover trozos enteros de código antiguo. Cuando haya aislado tales piezas de código antiguo y comprobado, que todo todavía funciona (ya que el código heredado nunca tiene pruebas .. así es como se convierte en "legado"), luego puede comenzar a dividirlo aún más, mientras se centra en separar la lógica empresarial de UI.


P.d. Yo mismo todavía estoy luchando para encontrar la mejor manera de lidiar con los puntos de vista. Este post es menos una respuesta y más como una instantánea de mi comprensión actual.

 70
Author: tereško,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-30 22:40:03

El segundo tutorial es la forma en que funciona el framework Code Igniter, y a la que estoy acostumbrado. Lo sigo incluso cuando no uso ningún marco en absoluto.

De hecho, el desarrollador debe poner en práctica los principios similares a MVC, de lo contrario puede hacer lasaña o espagueti incluso utilizando el marco orientado más similar a MVC.

Usando el enfoque "archivo PHP como plantilla de vista", idealmente uno usaría instrucciones PHP mínimas, básicamente solo para repeat-structures (foreach ($array as $item)), basic condicionales (if ($boolean)) y echo - como si fuera, de hecho, un lenguaje de plantillas, y nada más.

Por lo tanto, las etiquetas <?php ?>en los archivos de plantilla de la vista deben ser simplemente marcadores de posición, y nada más.

No se deben realizar consultas de base de datos, acceso al modelo, cálculos y similares en el archivo de plantilla de vista. Debería tratarse, básicamente, como un archivo HTML con marcadores de posición. (Con su asociado CSS y JavaScript. Las cosas pueden volverse más complejas cuando la aplicación depende mucho de JavaScript / AJAX...)

Siguiendo estos simples principios, efectivamente hacemos una cierta separación de la presentación de la lógica de negocio. Incluso sonando tan simple, estoy cansado de tratar con código de encendido de código que no lo sigue. Algunos usan "funciones auxiliares" para disfrazar las llamadas al modelo/base de datos, ¡y piensan que es una buena práctica! :-)

No se ve un require dentro de estos archivos de plantilla de vista PHP porque son necesarios en su lugar, desde el " edificio de vistas" método.

Por supuesto, uno no debe echo y/o print desde dentro de las funciones de controlador y modelo. Esto también es muy simple, pero también estoy cansado de ver el código spaghetti haciéndose eco de HTML desde el interior de los métodos de controlador CI.

En la práctica, el controlador llama a los métodos del modelo, construye todos los datos necesarios para la vista y, como último paso, llama a la vista (es decir, la construye y la genera), pasándole los datos ya obtenidos previamente.

Tiene sentido? No se si respondió a tu pregunta. Al menos, estos son mis "2 centavos".

 10
Author: J. Bruni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-16 19:26:50

Diferentes frameworks usan diferentes lógicas para asignar variables para ver y obtener su contenido. A continuación se muestra un ejemplo simple usando la función 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>

Espero que esto responda a su pregunta...

 1
Author: Jay Bhatt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-16 18:51:37

Se supone que debe pasar un método en la clase view todo lo que necesita para construir una vista independiente del formato de salida. La mayoría de los desarrolladores usarán algún tipo de motor de plantillas para construir la mayor parte de la página y luego rellenar el cuerpo con la información específica de la solicitud. Hay muchas maneras de hacer esto. También es bueno tener una clase de vista abstracta que defina métodos auxiliares para elementos comunes como formularios e entradas.

Esta capa se abstrae de modo que la lógica de su aplicación no tiene que cambiar si decide cambiar el diseño o el formato de salida de cualquier manera.

Editar: Cada módulo representado por un conjunto MVC tendría su propia vista que tiene una colección de métodos responsables de enviar su salida al navegador. Hay muchas maneras de ir, pero aquí hay un ejemplo:

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);
    }
}

Este es solo un ejemplo rápido para darle una idea de cómo podría ser un método de vista simple.

 1
Author: ogc-nick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-16 20:03:41

Cuando el navegador llama a una página, se cargará un controlador para esta. El controlador administra el ciclo de vida de la aplicación. Tomará datos del modelo, que solo se usa para obtener datos (tal vez de una base de datos). La vista es solo HTML, el controlador hará eco de la vista, y si es necesario, le pasará algunos parámetros.

 0
Author: hice3000,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-16 18:39:18
<?php

Vista de clase {

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
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-18 17:09:40

Compruebe este código:

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
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-18 17:44:39