patterns pattern php model-view-controller design-patterns repository-pattern

php - pattern - MVC y el patrón de repositorio: roles de controladores, modelos y repositorios?



laravel repository pattern (2)

¿Debería el controlador crear un objeto User y luego pasarlo al modelo?

No estoy seguro de lo que quiere decir con "pasar eso al modelo": el objeto User es el modelo. "Controlador" y "modelo" representan diferentes capas en el diseño, no son objetos específicos, y no debería haber un objeto UserModel separado como usted mencionó.

La interfaz del repositorio en sí se considera generalmente parte del modelo, aunque los objetos de dominio no deberían guardarse ellos mismos, esto debería hacerse en el controlador.

El trabajo de su controlador sería entonces interpretar la solicitud y crear un objeto User , luego usar el repositorio para guardar al usuario:

$user = new User(...); // based on Request $repository->save($user);

me parece que necesitaría tener un objeto de dominio que sea simplemente una estructura de datos simple sin ningún tipo de comportamiento

Esto no es cierto, puede y debe encapsular el comportamiento en los objetos de su dominio. En cuanto a cómo se implementa realmente la persistencia, un buen ORM debería ocuparse de la mayoría de los detalles y no debería tener que crear clases adicionales a mano.

Así que he estado estudiando el papel del patrón de repositorio como un medio para desacoplar la capa de persistencia de mis modelos en un marco de MVC. Antes de esto, podría tener mi UserModel llamando directamente a los métodos de registro activo para almacenar / recuperar objetos de dominio.

Aquí hay un boceto de lo que estoy pensando con respecto a la pila de llamadas en una solicitud que debería crear un nuevo User :

Aquí están mis preguntas:

  1. ¿Es esta una implementación correcta del patrón de repositorio?
  2. Entiendo que el controlador debe tomar la información del usuario de la solicitud y pasarla al modelo. ¿Cómo suele pasar eso? ¿Debería el controlador crear un objeto User y luego pasarlo al modelo? Estoy tan seguro de que no quiero pasar una serie de valores al modelo, ni quiero pasar 15 argumentos al método del modelo que crea un usuario.
  3. Para que este patrón realmente funcione, me parece que necesitaría tener un objeto de dominio que sea simplemente una estructura de datos simple sin ningún comportamiento y luego, si estoy usando un ORM, tendría un objeto ORM que lo haría describir cómo persiste el objeto. Inicialmente me resistí a esto porque se siente como un código duplicado, pero si realmente estoy separando la persistencia de la lógica comercial, esto sería necesario, ¿verdad? Por ejemplo, ¿qué pasa si voy con una tienda en memoria? Ya no usaría el objeto ORM.

¿Estoy pensando correctamente aquí? Es esto aceptable. Por favor, ayúdame a conectar los puntos en mi cabeza.


1. ¿Es esta una implementación correcta del patrón de repositorio?

No estoy seguro de dónde has estado haciendo esa investigación, pero te equivocaste.

  • Repositorios como para separar los objetos de dominio de los mapeadores de datos .

  • No hay tal cosa como "modelos". El modelo en patrón de diseño MVC es una de las capas principales: capa de presentación y capa de modelo .

  • Y el patrón de repositorio es incompatible con el patrón de registro activo (anti), que combina el dominio y la lógica de almacenamiento en una sola instancia, lo que provoca una gran violación de SRP .

Para utilizar un ejemplo del mundo real para, cuándo y cómo usar un repositorio aquí hay un ejemplo:

Está creando una herramienta de administración de documentos, donde dichos documentos pueden provenir de varias fuentes (por ejemplo: base de datos SQL local, servicio SOAP y caché). En esta situación, crea un repositorio, que se ocupa del "enrutamiento" del almacenamiento. Es la parte de la aplicación, que decide qué correlacionador de datos usar para almacenar / recuperar cada documento.

El objetivo del repositorio es separar la lógica del dominio de la interacción con el almacenamiento. Para el sistema, que se describió anteriormente, un repositorio también permitiría agregar nuevas fuentes de datos, sin necesidad de reescribir grandes cantidades de código (si lo hubiera). Simplemente podría agregar otro tipo de asignador para el documento.

2. ¿Debería el controlador crear un objeto User y luego pasarlo al modelo?

Para empezar, el controlador en sí no debe crear nada. En su lugar, su controlador debe usar una fábrica para adquirir la instancia del objeto que necesita. Esta fábrica se puede proporcionar al controlador a través de un constructor u otro método. Esto se llama: Inyección de dependencia (para obtener más información al respecto, vea esta conferencia ).

Además, como se señaló anteriormente, el modelo es una capa, no cualquier clase u objeto específico. La responsabilidad del controlador es alterar el estado de la capa del modelo (al pasarle datos). Podrías interactuar con objetos de dominio y mapeadores (o repositorios) directamente en el controlador, pero eso significaría filtrar parte de la lógica de negocios en el controlador. En su lugar, se recomienda usar servicios , que luego manipula dichos objetos de dominio y estructuras relacionadas con el almacenamiento.

En cuanto al problema con el parámetro 10+, que requeriría para la creación de una nueva cuenta de usuario, asumamos que tiene acción con la siguiente huella:

public function postUser( Request $request ) { .... }

Si se llama a la acción con una instancia de Request específica, tiene dos opciones para lidiar con una gran cantidad de parámetros:

  1. Envuelva la instancia en un decorador , lo que le permitiría llamar a un único método para formar los datos de la solicitud en una matriz específica. Luego pasa esta matriz al servicio (s).

  2. Forme la matriz dentro de la acción del controlador y páselo, donde se requieren los datos.

La primera solución es más adecuada para aplicaciones a gran escala, donde dicha formación de datos se requeriría repetidamente a través del código. Pero en proyectos pequeños / medianos, la segunda opción es el enfoque de sentido común.

La cosa es que el trabajo del controlador es tomar la entrada del usuario y distribuirla a la capa del modelo y a la vista actual. Y la formación de dicha matriz encaja a la perfección con este mandato.

3. (...) objeto principal que es solo una estructura de datos simple sin comportamiento y luego (...)

No. El objeto de dominio no es "datos simples". Es donde reside la mayor parte de la lógica comercial del dominio en la aplicación.

Y olvídate de los ORM mágicos. El primer paso para implementar un repositorio es separar el dominio y la lógica de almacenamiento. El objeto de dominio maneja las reglas de validación y comerciales, el asignador trata con la persistencia y la integridad de los datos (pequeño ejemplo aquí ).

Otra cosa que debes tener en cuenta es que los repositorios para aplicaciones web realmente no interactúan con la persistencia en memoria (aparte de la caché). En su lugar, su repositorio estaría malabarizando mapeadores para diferentes fuentes de datos.