Cuando desarrollamos un sitio web usando el patrón Modelo-Vista-Controlador está el riesgo de mal interpretar el rol de los controladores, las vistas y los modelos. El resultado de esto es controladores enormes y modelos pequeños lo que hace difícil probar y mantener nuestra aplicación. El objetivo de esta sección es dar una comprensión general sobre el código que se puede colocar en la clase controladora, el que se puede colocar en la plantilla de vista y el código que se puede colocar en una clase modelo.
La idea que está detrás del termino "controladores flacos" (skinny controller) es que generalmente en nuestras clases controladoras solo colocamos código que:
$_GET
, $_POST
, $_FILES
y otras variables PHP).ViewModel
.A controller class should avoid:
Para un ejemplo de un controlador "flaco" miremos más abajo la clase
CurrencyConverterController
. Este controlador provee el método de acción
"convert" cuyo objetivo es convertir un cantidad de EUR a USD. El usuario pasa
la cantidad de dinero a través de la variable GET "amount".
class CurrencyConverterController extends AbstractActionController
{
// Currency converter model
private $currencyConverter;
// Constructor. It's purpose is to "inject" dependencies.
public function __construct($currencyConverter)
{
$this->currencyConverter = $currencyConverter;
}
// The "convert" action displays the converted money amount
public function convertAction()
{
// Get the money amount from GET
$amount = (float)$this->params()->fromQuery('amount', -1);
// Validate input data
if($amount<0) {
// Money amount is missing
$this->getResponse()->setStatusCode(404);
return;
}
// Pass the data to the CurrencyConverter model
$convertedAmount = $this->currencyConverter->convertEURtoUSD($amount);
return new ViewModel([
'amount'=>$amount,
'convertedAmount'=>$convertedAmount
]);
}
}
El método de acción del controlador anterior hace lo siguiente:
Toma los datos pasados por el usuario (línea 16). Estos datos son usualmente
parte del objeto Request
que se pueden recuperar usando el método del controlador
getRequest()
o por medio del complemento para controladores Params
.
Ejecutar revisiones básicas sobre los datos que el usuario pasa (línea 19) y si los datos no existen o son inválidos colocamos un código de error HTTP (línea 21).
Pasar la cantidad de dinero al modelo CurrencyConverter
(línea 26) mediante
el llamado al método convertEURtoUSD()
. Luego el método regresa la cantidad
convertida.
Construye el contenedor de variables ViewModel
y le pasa los datos resultantes
(línea 28). A este contenedor de variables se puede acceder luego en la
correspondiente plantilla de vista responsable de la presentación de los datos.
Como necesitamos mantener nuestros controladores tan flacos como sea posible la mayoría de la lógica de negocio de nuestra aplicación se debería colocar dentro de las clases modelo. En una aplicación diseñada correctamente bajo el patrón Modelo-Vista-Controlador los modelos se ven "enormes". Una clase de modelo puede contener código que:
Ejecuta filtrado de datos y validaciones complejas. Como los datos que recuperamos en el controlador están entrando a nuestra aplicación desde el mundo exterior en el modelo tenemos que esforzarnos por verificarlos y asegurar que estos no rompan nuestros sistema. El resultado de esto es un sitio web seguro que resiste los ataque de los crackers.
Manipula los datos. Nuestros modelos deben manipular los datos, por ejemplo, cargar los datos desde la base de datos, guardarlos en la base de datos y transformar los datos. Los modelos son el lugar correcto para guardar las consultas de base de datos, los funcionalidades de lectura y escritura de archivos, etc.
En las clases de modelo no es recomendable:
Acceder a los datos de las petición HTTP, $_GET
, $_POST
y otras variables
PHP. Ese es el trabajo del controlador: extraer los datos y pasarlos a la
entrada del modelo.
Producir código HTML u otro código específico de la presentación. El código de presentación puede variar dependiendo de la petición del usuario y es mejor colocarlo en la plantilla de vista.
Si seguimos estos principios encontraremos que nuestros modelos son fáciles de probar porque ellos tienen identificados claramente las entradas y las salidas. Podemos escribir pruebas unitarias que pasan determinados datos de prueba como entrada a los modelos, recuperar los datos de salida y verificar que los datos son correctos.
Si estamos confundidos sobre donde colocar un determinado segmento de código o en el controlador o en el modelo, podemos intentar preguntarnos a nosotros mismos: ¿Es este pedazo de código una regla del negocio importante que necesita ser cuidadosamente probada? si la respuesta es sí debemos colocar el código en un modelo.
Como la mayoría de la lógica se guarda en los modelos, nuestras plantillas de vista serán tan simples como sea posible para producir la presentación de los datos que se pasan a través del contenedor de variables. En una plantilla de vista podemos:
Tener código HTML estático.
Recuperar los datos desde el contenedor de variables e imprimirlos en el flujo de salida PHP.
Si un controlador pasa un determinado modelo por medio del contenedor de variables podemos consultar los datos del modelo (por ejemplo, podemos recuperar las columnas de una tabla de base de datos e imprimirlas).
Contener estructuras de control simples de PHP como: if
, foreach
, switch
,
etc. Esto permite variar la presentación dependiendo de las variables pasadas
por el controlador.
No es recomendable que las plantillas de vista:
Acceder a los datos de la petición HTTP y a las variables PHP super globales.
Crear modelos, manipularlos y modificar el estado de la aplicación.
Si seguimos estos principios encontraremos que nuestras vistas se pueden sustituir fácilmente sin modificar la lógica de negocio de nuestra aplicación. Por ejemplo, podemos fácilmente cambiar el diseño de nuestra página web o introducir temas intercambiables.