Vistas mas legibles usando Presenters en Laravel

presenter-en-laravel

No sé si alguna ves te ha pasado, que con el tiempo tus vistas a pesar de que las organices para hacerlas mas manejables, llegan a un punto donde comienzan a tener mucha lógica y comiences a preguntarte si es posible mejorarlas de alguna forma.

Pues bien si es posible y no estas solo,

Hace poco mas de una semana atrás, tuvimos un charla sobre este tema en nuestro slack y platicamos sobre como puedes tener vistas mas ligeras moviendo parte de su lógica a algo que se conoce como Presenter.

Esta estrategia no es nueva, pero puede ser muy útil conocer su uso. Y si no te suena el nombre no te preocupes que vamos a ver de que se trata y como podemos sacarle provecho.

 

Qué son los Presenter

En realidad el Presenter es parte de un modelo de arquitectura llamado Model View Presenter que es una variante del modelo MVC.

El Presenter actúa sobre el modelo y la vista. y su función es obtener datos del modelo para formatearlo para que los presente la vista sin tener que usar lógica adicional.

¿Que dijo?

si esto parece confuso, no te preocupes vamos a verlo con mas detalle.

Como funciona este patrón

Si pongo esto en un diagrama, el Presenter se ve algo como esto:

model-view-presenter

Bien veamos como funciona esto del Presenter:

vamos a suponer que hacemos un Request a la siguiente ruta

http://domain/users/1

En nuestro Resource Controller esa petición se procesa de la siguiente forma

Como estoy utilizando implicit binding obtengo el usuario y lo paso a la vista.

Pero espera, ¿donde esta el Presenter?

Sabía que te darías cuenta, el presenter como muestra el diagrama esta entre la vista y el controlador.

Así que corrigiendo nuestro ejemplo, quedaría como sigue

Esto quiere decir que el Presenter es simplemente una clase que actúa como el modelo y que ademas puede pasar lógica adicional a la vista. que de otra forma terminaría en el modelo, el controlador o la vista,

donde no debe de estar!

Pero que te parece si dejamos la teoría y vamos a lo nuestro con un ejemplo.

Sigamos con el ejemplo

 

Vamos a suponer que la vista del ejemplo previo presenta los datos del usuario mediante un card.

user-card

Algo sencillo sin mucha complicación,

y cuando vamos a la vista esperando ver algo sencillo, pero nos topamos con este código

Tres cosas puedes notar de este ejemplo

  1. La primera es que tenemos una serie de condiciones para establecer una imagen de acuerdo al sexo del usuario, cuando este no a subido una imagen.
  2. La segunda es la llamada a la clase App\User
  3. La tercera es la forma es que se esta llamando a la fecha de creación del usuario para darle formato

Ahora mi pregunta seria ¿Crees que esto debe de estar en la vista?

Pienso que la vista solo debiera de imprimir los datos sin complicaciones, en lugar de decidir cual imagen toca de acuerdo con el sexo del usuario.

Así que, me gustaría que la vista se viera de esta forma

¿Qué te parece?

Ahora, ¿Cómo hacemos semejante maravilla?

Es mas sencillo de lo que te imaginas, ya que ahora sabemos que podemos usar un Presenter, solo tenemos que crearlo.

Cómo implementamos el Presenter

vamos a crear nuestra clase UserPresenter y en ella vamos a crear la logica para que funcione el método getAvatar()

Como algo adicional agregue que se pueda establecer el idioma de acuerdo a la configuración de la aplicación (setLocale()).

Pero es muy probable que te preguntes para que sirve la parte que llama al método mágico __call y lo que hace es permitirme seguir llamando a los métodos y propiedades del modelo User sin tener que crear nuevos métodos en la clase UserPresenter.

De esta forma no tengo que agregar cambios adicionales.

Muy bien, ahora nos falta agregar el método since() y el método hasAvatar() que debiste de ver en la clase UserPresenter, pero estos dos métodos los he mandado al Modelo User.

Estos dos métodos lo e creado aquí, porque creo que es donde deben de estar, si a tí no te gusta o crees que no deben de estar en ese lugar, los puedes pasar al Presenter no pasa nada.

Muy bien, ya solo nos falta hacer los cambios en el Controller como sigue.

Y listo hemos terminado, ahora la vista luce mas legible, no tuviste que hacer muchos cambios y eres pura felicidad!

Pero….

¿Que pasa si tu modelo tienes relación con otro?

laugh face

Si no lo habías pensado, este es un punto importante, ya que si el modelo relacionado tiene también un Presenter no lo vamos a poder usar!!

Mejoremos el Presenter

 

Pero tranquilo, que existen soluciones

  1. Usar el Patrón de diseño Decorator
  2. Delegar el Presenter desde el Modelo

Como no hemos visto nada de los decoradores esta opción la vamos a dejar por fuera.

Así que vamos a usar la siguiente, que sería lo opuesto que tenemos en este momento.

Es decir que el modelo delegue las peticiones que vayan hacia UserPresenter mediante el uso del método __call, de esta forma si tenemos relaciones las podemos usar sin problemas ademas de los métodos del presenter.

Para este caso mi elección sera mediante un Trait que se encargara de instanciar el UserPresenter y podamos usarlo desde el Modelo, en este caso desde User.

Ya que movimos la llamada a __call, va ser necesario quitarlo del presenter, así que no olvides borrar esa parte!

En nuestro modelo User vamos a usar el trait de la siguiente forma:

Para finalizar tenemos que cambiar el controlador

Listo, ahora ya todo funciona como debe de ser.

El resumen

Como puedes ver el Presenter puede ser muy util para reducir la complejidad de las vistas y puedes mantener el código de forma mas sencilla.

Pero debes de estar atento de mantener el equilibrio y pensar muy bien que lógica mueves al Presenter ya que puede terminar con lógica que no le pertenece.

También existen otras formas de implementar los presenter usando decoradores y puedes probar cosas mas al estilo Laravel implementado la interfaz Responsable.

Finalmente deja tus comentarios y no olvides compartir!

Comparte este artículo

Entra en la discusión y deja tu comentario

Veces