En MVC, ¿puede / debe realizarse la recuperación de datos básicos del Modelo en la Vista?

10

Dado el concepto de 'controladores flacos, modelos gordos' y la aceptación general de que las Vistas pueden llamar directamente a los Modelos cuando requieren datos para la salida, ¿debería uno considerar manejar las partes de 'obtener y mostrar' de las solicitudes dentro de las Vistas y no el Controlador? Por ejemplo (intentó mantener el código bastante genérico):

Controlador

<?php

class Invoice extends Base_Controller {

    /**
     * Get all the invoices for this month
     */

    public function current_month() {

        // as there's no user input let's keep the controller very skinny,
        // DON'T get data from the Model here, just load the view

        $this->load->view('invoice/current_month');

    }

}

Ver

<?php

// directly retrieve current month invoices here

$invoices = $this->invoice_model->get_current_month();

// get some other display-only data, e.g. a list of users for a separate list somewhere on the page

$users = $this->user_model->get_users();

?>

<h1>This month's invoices</h1>

<ul>
<?php foreach ($invoices as $invoice) { ?>

<li><?php echo $invoice['ref']; ?></li>

<?php } ?>
</ul>

Para mí, esto tiene al menos algún sentido en los casos en que una solicitud es esencialmente solo una Vista. ¿Por qué el controlador debe recopilar y transmitir los datos a la vista cuando solo puede recuperarlos? Esto deja al Controlador abierto para el procesamiento puramente de 'Nivel de aplicación' (por ejemplo, manejo de solicitudes GET / POST, administración de derechos de acceso y permisos, etc.), así como para mantener los Modelos reutilizables y todas las demás cosas buenas.

Si este ejemplo se extendiera para permitir que un usuario filtre los resultados, el Controlador solo manejaría la POST desde el formulario y pasaría los filtros a la Vista, que luego solicitaría nuevamente los datos, esta vez con los filtros.

¿Es este un enfoque válido para desarrollar una aplicación MVC? ¿O estoy pasando por alto una parte importante del papel que debe desempeñar un controlador?

Adam Westbrook
fuente

Respuestas:

17

Sí, técnicamente se puede hacer. No, no debe hacerse. Y sí, te estás perdiendo un poco de lo que el controlador está ahí para hacer.

El controlador está ahí para desacoplar la Vista del Modelo. El desacoplamiento es beneficioso porque debe ver la Vista como un código casi desechable. A medida que cambia la tecnología de la interfaz de usuario, desea minimizar el retrabajo requerido para generar una nueva Vista. El controlador permite ese desacoplamiento y proporciona un lugar para su código que vivirá a través de las tecnologías de IU.

Funciona a la inversa también si necesita agregar o cambiar su Modelo. Todos los cambios ascendentes estarán contenidos en el Controlador y sus Vistas se dejarán en paz.

El otro riesgo es que, si bien la Vista es muy simple ahora , tiene menos garantía de que seguirá siendo tan simple durante toda su vida. Al llamar al Modelo directamente desde la Vista (muy simple), ha abierto la puerta un poco para permitir que las malas prácticas adicionales entren más tarde cuando la Vista muy simple necesita volverse no tan simple. Un futuro desarrollador se verá tentado a hacer más llamadas de Modelo desde la Vista no tan simple en lugar de refactorizar el código e interactuar con un Controlador.


fuente
1
Gran respuesta, gracias. Extender un poco su escenario de "mirar hacia el futuro"; Si hay información común en una página que está separada de lo que se solicita (por ejemplo, el usuario está viendo un producto específico, se muestra una lista general de las "últimas ofertas especiales" a un lado) ¿cómo / dónde se debe hacer la llamada offers_model->get_latest()? Agregar esto en cada método en el controlador (como he intentado tontamente antes) parece excesivo y claramente SECO.
Adam Westbrook
2
@AdamWestbrook Echa un vistazo a MVVM. La parte de ViewModel de eso puede abordar este problema específico. Puede agregar el offers_model->get_latest()a una ProductViewModelclase base o algo similar.
Zachary Yates
1
Genial, definitivamente investigaré MVVM, gracias de nuevo.
Adam Westbrook
Muy buena respuesta, definitivamente mantendrá este destacado. Personalmente, también soy un gran admirador de MVVM :)
Benjamin Gruenbaum
@BenjaminGruenbaum ¿Estás utilizando MVVM en PHP? Si es así, ¿está utilizando un marco particular para ello?
Adam Westbrook
6

Dado el concepto de 'controladores flacos, modelos gordos' y la aceptación general de que las vistas pueden llamar directamente a los modelos cuando requieren datos para la salida

No esto no es correcto. Ver no puede llamar directamente a Modelos. Las vistas no deberían tener acceso a los objetos del Modelo, a menos que por alguna razón el programador haya expuesto esos objetos a la Vista.

¿debería uno considerar manejar las partes 'obtener y mostrar' de las solicitudes dentro de las Vistas y no el Controlador?

Básicamente, eso borra el Controlador y anula el punto de tenerlos.

¿Por qué el controlador debe recopilar y transmitir los datos a la vista cuando solo puede recuperarlos?

El controlador no recopila los datos. El modelo hace la recolección de los datos. El controlador decide si estos datos deben pasarse a la vista. La vista solo hace la presentación de los datos.

Si este ejemplo se extendiera para permitir que un usuario filtre los resultados, el Controlador solo manejaría la POST desde el formulario y pasaría los filtros a la Vista, que luego solicitaría nuevamente los datos, esta vez con los filtros.

No.

El Controlador verifica si los datos PUBLICADOS son válidos, luego pasa estos datos como opciones al Modelo, que luego consultaría la fuente de datos y devolvería los datos, y el Controlador los pasa a la Vista.

¿Es este un enfoque válido para desarrollar una aplicación MVC? ¿O estoy pasando por alto una parte importante del papel que debe desempeñar un controlador?

El controlador funciona como un controlador de las solicitudes del navegador. Un despachador envía la solicitud a la acción de un controlador, que a su vez, extiende la solicitud a los Modelos. Los modelos contienen toda la lógica empresarial (esta es la parte importante) y devuelven los datos al controlador. El controlador puede entonces simplificar y ajustar los datos para que sea más fácil para la Vista presentarlos.

El punto de vista es desacoplar la estructura y la dependencia entre la presentación de HTML y DataSource. Si bien esto puede ser difícil. Las vistas no siempre presentan datos que provienen directamente de un modelo. El controlador a menudo agrega datos adicionales que son relevantes.

Estoy seguro de que hay muchos tutoriales en MVC. Recomiendo leer algunos de ellos.

Reactgular
fuente
Gracias mathew Para aclarar, hasta ahora siempre he desacoplado la Vista y el Modelo con el Controlador como se leyó y sugirió. Sin embargo, desde que comencé a leer sobre cómo mantener Controladores 'flacos', me he estado preguntando qué debería / podría sacarse de ellos, ¡parece que el proceso de pensamiento que me llevó a esta pregunta fue un paso o dos demasiado lejos!
Adam Westbrook
Cuando comience a obtener Modelos utilizados por muchos controladores. La necesidad de que sean gordos se vuelve muy clara. Cuando la Vista comienza a contener una gran cantidad de PHP, entonces sabes que tu controlador es demasiado delgado. Cuando tus controladores son muy gordos. Es difícil lograr que otros controladores funcionen de la misma manera (por ejemplo, agregando un servicio API).
Reactgular
3

Su pregunta me pareció muy interesante porque me encontré con el mismo problema mientras aprendía Python recientemente.

Si bien las respuestas dadas son un argumento convincente, pensé que agregaría otra opinión que encontré en la que la Vista obtiene el estado del Modelo sin pasar por el Controlador.

MVC

Es importante tener en cuenta que tanto la vista como el controlador dependen del modelo. Sin embargo, el modelo no depende de la vista ni del controlador. Este es uno de los beneficios clave de la separación. Esta separación permite que el modelo se construya y pruebe independientemente de la presentación visual. La separación entre vista y controlador es secundaria en muchas aplicaciones de cliente rico y, de hecho, muchos marcos de interfaz de usuario implementan los roles como un solo objeto. En las aplicaciones web, por otro lado, la separación entre la vista (el navegador) y el controlador (los componentes del lado del servidor que manejan la solicitud HTTP) está muy bien definida.

Model-View-Controller es un patrón de diseño fundamental para la separación de la lógica de la interfaz de usuario de la lógica de negocios. Desafortunadamente, la popularidad del patrón ha dado lugar a una serie de descripciones defectuosas. En particular, el término "controlador" se ha utilizado para significar cosas diferentes en diferentes contextos. Afortunadamente, el advenimiento de las aplicaciones web ha ayudado a resolver parte de la ambigüedad porque la separación entre la vista y el controlador es muy evidente.

En Programación de aplicaciones en Smalltalk-80: Cómo usar el Modelo-Vista-Controlador (MVC) [Burbeck92], Steve Burbeck describe dos variaciones de MVC: un modelo pasivo y un modelo activo.

El modelo pasivo se emplea cuando un controlador manipula el modelo exclusivamente. El controlador modifica el modelo y luego informa a la vista que el modelo ha cambiado y debe actualizarse (consulte la Figura 2). El modelo en este escenario es completamente independiente de la vista y el controlador, lo que significa que no hay medios para que el modelo informe cambios en su estado. El protocolo HTTP es un ejemplo de esto. No hay una manera simple en el navegador para obtener actualizaciones asincrónicas del servidor. El navegador muestra la vista y responde a la entrada del usuario, pero no detecta cambios en los datos del servidor. Solo cuando el usuario solicita explícitamente una actualización, el servidor es interrogado por los cambios.

MVC - Modelo pasivo

No estoy en condiciones de decir cuál de las opiniones es "correcta", y para ser honesto, estoy un poco más confundido después de leer las respuestas aquí y el artículo vinculado.

Texto completo del artículo aquí .

alnafie
fuente
Correcto, y la otra cosa que agrega confusión es el cliente-servidor, que el MVC original de SmallTalk realmente no tenía en cuenta. En el cliente-servidor (p. Ej., Con javascript) hay modelos, vistas y controladores orientados a la presentación en el cliente, y vistas y controladores orientados al dominio en el servidor, aunque el servidor también realiza un procesamiento orientado a la presentación que agrega confusión. Además, a veces queremos que las vistas de un dominio tengan cierta persistencia, lo que significa que los parámetros de la vista forman su propio modelo, que no es necesariamente parte del modelo de dominio.
Erik Eidt
Gracias por el enlace, ¡sabía que no estaba enojado al pensar esto! Esto es esencialmente lo que había estado haciendo antes de llevar la idea demasiado lejos, siempre y cuando el Modelo no dependa de nada, ¿qué importa cómo / dónde se accede? Todavía no he decidido qué enfoque voy a adoptar en mi próximo desarrollo, pero esto definitivamente ayuda.
Adam Westbrook
1

Otra cosa a considerar es que parece haber cargado automáticamente user_modely invoice_modelpermitir que la vista acceda a ellos. Para que esto funcione de manera confiable, probablemente cargue automáticamente todos sus modelos (porque $this->load->model()simplemente se ve mal en una vista, ¿no es así?)

Hacer esto hincha innecesariamente tu pila al cargar un montón de cosas que quizás nunca se usen. Parte de la razón para tener múltiples modelos es permitirle encapsular la lógica relacionada y cargar solo lo que necesita para una tarea determinada.

Esto se parece a CodeIgniter. He desarrollado mucho CI y puedo compartir por experiencia personal que realmente no quieres cargar más de lo que realmente debes. Intente agregar $this->output->enable_profiler(TRUE);el constructor de un controlador y jugar con cargas automáticas (incluidos los ayudantes database): probablemente verá un cambio significativo en los tiempos de carga y ejecución, pero especialmente en la asignación de memoria.

msanford
fuente
1
Puntos positivos, tienes razón, esto se basa en CI, aunque eliminé parte de la sintaxis específica para mayor claridad. Me he acostumbrado a 'cargar automáticamente' casi todo por mucho tiempo y por razones SECAS, parecía un poco loco tener mucho de lo mismo load->modelen la mayoría de los controladores y métodos. No usar una función de carga automática adecuada es una de las cosas que más me disgustan de la compatibilidad con versiones anteriores de CI, pero esa es otra discusión ...
Adam Westbrook
0

La respuesta corta es que la forma de su muestra de código es engañosamente intuitiva. Parece que este es un camino "fácil de pensar".


Problema # 1

Tu Modely Viewobjetos estarán estrechamente acoplados.

Si alguna vez tiene que agregar o quitar métodos en el Model, entonces es posible que tenga que modificarlos en Viewconsecuencia.

Básicamente, MVC se deriva de los patrones de Comando y Observador . Desea un 'Modelo' independiente que se manipule a través de una interfaz / API en la que Controllerpueda engancharse (es decir, delegación).

Con frecuencia, esto significa inyectar Model e Viewinstancias en Controlleray almacenarlas como propiedades de dicho Controller. Luego, utilizando un método de Controller(es decir, un comando) como área de trabajo, pase datos a a View desde Model ( después de que el `Modelo haya terminado de actualizar el estado de la aplicación ).

Datos que pasan (arrays, objetos iterables, lo que sea) mantiene al tanto de acoplamiento entre Modely Viewcasos pierden . Si inyecta la Modelinstancia en el View, vea el Problema # 1 arriba.

Recuerde, Viewspodría ser HTML, JSON, Texto, XML, encabezados HTTP, YAML o casi cualquier cosa, siguiendo una metodología de transferencia de estado de representación (REST) .

Por lo tanto, la clave para comprender cómo gestionar la relación entre Modely Viewses ver la relación por lo que es, ¡ uno a muchos (potencialmente)! Esto es exactamente para lo que se diseñó el patrón Observer .

Si bien la mayoría de las configuraciones solo tienen que ver una vista a la vez, ¡no hay nada que impida que el patrón arquitectónico MVC actualice varias vistas a la vez! Uso de aplicaciones CRUD web tradicionales hace que la gente piensa en un uno-a-uno manera, pero eso es el ejemplo más pequeño de cómo el patrón de observador podría trabajar ( uno-a-muchos es el otro ).

Por lo tanto, si tenía uno Modely múltiples Views, el potencial dolor de cabeza de actualizar todo el Views'código de implementación porque cambió algo en la Model'sAPI / métodos ahora se agudiza .

Pase datos a Views , no instancias de Models .

Anthony Rutledge
fuente