Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Separación Código en Tres Capas - Tutorial MVC Con PHP
Separación Código en Tres Capas - Tutorial MVC Con PHP
¿Qué es MVC?
Este código es lo necesario para cumplir con el proposito de listar los artículos
<?
// conexion a la base de datos
$cn = mysql_connect('localhost', 'usuario', 'clave');
mysql_select_db('db', $cn);
<?php
//cerramos la conexion
mysql_close($cn);
?>
Observaciones
controlador.php
<?
$cn = mysql_connect('localhost', 'usuario', 'clave');
mysql_select_db('db', $cn);
while($articulo = mysql_fetch_assoc($resultado))
{
$articulos [] = $articulo;
}
mysql_close();
require('vista.php');
?>
vista.php
<h1>Listado de Articulos</h1>
<table>
<tr> <th>Fecha</th> <th>Titulo</th> </tr>
<?php foreach($articulos as $articulo): ?>
<tr>
<td><?php echo $articulo ['fecha'] ?></td>
<td><?php echo $articulo ['titulo'] ?></td>
</tr>
<?php endforeach;?>
</table>
De esta manera tenemos separada en el controlador.php casi todo el código php con la
lógica de negocios, mientras que en vista.php solo recorremos un array con datos.
Lo recomendable en la vista seria utilizar instrucciones PHP mas conocidad, como: if,
endif, foreach, endforeach . Y no utilizarlas con llaves “{” , ya que dificulta reconocer
donde empieza y termina.
Otro problema seria si queremos utilizar nuevamente el listar articulo en otra pagina,
tendríamos que reescribir el controlador.php de nuevo.
Utilizando el Modelo
modelo.php
<?php
function getArticulos()
{
$cn = mysql_connect('localhost', 'usuario', 'clave');
mysql_select_db('db', $cn);
while($articulo = mysql_fetch_assoc($resultado))
{
$articulos [] = $articulo;
}
mysql_close();
}
?>
controlador.php
require('modelo.php');
$articulos = getArticulos();
require('vista.php');
Despues de esta separación el controlador quedaría tan solo como un agente para pasar
datos del modelo hacia la vista, pero en aplicaciones mas complejas el controlador es
quien realiza las tareas de autenticación de usuarios, manejo de sesiones, filtrar y validar
entradas de datos por GET o POST.
Si se diera el caso de cambiar de gestor de base de datos, solo tendríamos que actualizar
la capa de abstracción de la base de datos
Abstracción de datos
function cerrarConexion($cn)
{
mysql_close($cn);
}
Acceso a Datos
function getTodosLosArticulos()
{
$cn = crearConexion('localhost', 'usuario', 'clave');
$articulos = array();
while ($articulo = getResultado($resultado))
{
$articulos [] = $articulo;
}
cerrarConexion($cn);
return $articulos;
}
TUTORIAL 2
¿Qué es MVC?
Un pequeño ejemplo
1. Marcos entra a nuestro sitio mediante la URL www.example.com/items/listar.
2. Se carga el Controlador Items para ejecutar la acción de Listar.
3. El controlador solicita al modelo que le entregue un arreglo con todos los items
que hay almacenados en la base de datos.
4. Una vez que posee dicha información le indica a la vista que va a utilizar la
plantilla correspondiente al listado de items y le provee el arreglo con todos los
usuarios.
5. La vista, por su parte, toma el arreglo de items y los muestra uno a uno en la
plantilla que le indico el controlador.
6. Finalmente Marcos recibe el listado de items; lo observa un instante y decide
que quiere agregar un nuevo item por lo que hace click en un enlace que lo lleva
a la URL www.example.com/items/agregar.
7. Se repite el proceso desde el paso 1 pero con la nueva URL
Vamos al codigo
Para ir de a poco tomaré un ejemplo sencillo similar a los que utilice cuando hable de
PHP Data Objects y lo iré separando en capas paso a paso. El ejemplo que voy a utilizar
es el siguiente:
1 < ?php
2 require 'conexion.php';
3 $db = new PDO('mysql:host=' . $servidor . ';dbname=' . $bd,
4 $usuario, $contrasenia);
5 $consulta = $db->prepare('SELECT * FROM items WHERE id_item = ? OR
6 id_item = ?');
7 $consulta->execute(array(2, 4));
8 $items = $consulta->fetchAll();
9 $db = null;
10 ?>
11 < !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
12 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
13
14 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
15 <head>
16 <meta http-equiv="Content-Type" content="text/html;
17 charset=utf-8"/>
18 <title>PDO - Jourmoly</title>
19 </head>
20 <body>
21 <table>
<tr>
<th>ID
22
</th><th>Item
23
</th></tr>
24
< ?php
25
foreach($items as $item)
26
{
27
?>
28
<tr>
29
<td>< ?php echo $item['id_item']?></td>
30
<td>< ?php echo $item['item']?></td>
31
</tr>
32
< ?php
33
}
34
?>
35
</table>
36
<a href="index.php">Menú</a>
37
</body>
</html>
Ver Ejemplo
Nada del otro mundo, es un simple listado común presentado en una tabla HTML.
Separaremos dicho ejemplo, por el momento, en 3 ficheros. Uno corresponderá al
modelo, otro a la vista y el tercero será el controlador.
modelo.php
< ?php
1
$db = new PDO('mysql:host=' . $servidor . ';dbname=' . $bd, $usuario,
2
$contrasenia);
3
$consulta = $db->prepare('SELECT * FROM items');
4
$consulta->execute();
5
$items = $consulta->fetchAll();
6
?>
¿Y cual es la vista?
La vista es quien representa la información para que el usuario la pueda entender, en
este caso, el HTML, la tabla y todo lo usado para mostrar la información forma parte de
la vista.
vista.php
¿Y el controlador?
El controlador es el que permite que todo funcione.
controlador.php
1 < ?php
2 //Se incluye el modelo
3 require 'modelo.php';
4
5 //En $items tenemos un arreglo con todos los items gracias al modelo
6
7 //Ahora la vista recibe dicho arreglo para mostrarlo por pantalla
8 require 'vista.php';
9 ?>
Por último, tendremos un fichero mas index.php que lo único que hará es incluir algunas
variables de configuración y nuestro controlador. Es decir, para ver el resultado del
script entraremos por index.php
Ver ejemplo
El ejemplo anterior esta bien para un primer acercamiento, pero cuando trabajamos a
diario las cosas no son tan sencillas como en este caso, una sola sección o
elemento(items), una sola acción(listar), etc. Lo mas normal es que necesitemos de
varios controladores y que cada controlador tenga varias acciones. A su vez, cada
controlador puede utilizar uno o mas modelos como así también plantillas. Para lograr
todo esto, es necesario que automaticemos un poco el primer ejemplo para que admita,
en principio, varios controladores y acciones.
Como primera medida vamos a crear una estructura de ficheros para que que todo quede
mas o menos ordenado, sencillo:
controladores/
.....itemsControlador.php
modelos/
.....itemsModelo.php
vistas/
.....listar.php
index.php
itemsModelo.php
< ?php
1
global $servidor, $bd, $usuario, $contrasenia;
2
$db = new PDO('mysql:host=' . $servidor . ';dbname=' . $bd,
3
$usuario, $contrasenia);
4
5
function buscarTodosLosItems($db)
6
{
7
$consulta = $db->prepare('SELECT * FROM items');
8
$consulta->execute();
9
return $consulta->fetchAll();
10
}
11
?>
itemsControlador.php
< ?php
1
function listar()
2
{
3
//Incluye el modelo que corresponde
4
require 'modelos/itemsModelo.php';
5
6
//Le pide al modelo todos los items
7
$items = buscarTodosLosItems($db);
8
9
//Pasa a la vista toda la información que se desea
10
representar
11
require 'vistas/listar.php';
12
}
13
?>
Como verán los únicos cambios han sido armar los scripts con funciones, de modo que
cada fichero pueda tener mas de una de ellas y puedan ser llamadas en cualquier
momento e independientemente.
De ahora en mas, nuestro fichero index.php será quien se encargue de averiguar cual es
el controlador y acción que busca el usuario, incluirá los archivos que sean necesarios y
ejecutara la acción solicitada. Todos los accesos a nuestro sistema serán por medio de
index.php y las URL serán similares a las siguientes:
www.example.com/index.php?controlador=items&accion=listar
www.example.com/index.php?controlador=items&accion=agregar
www.example.com/index.php?controlador=items&accion=eliminar
www.example.com/index.php?controlador=usuarios&accion=listar
Ahora solo nos queda hacer un pequeño script que interprete nuestra URL y llame al
controlador y la acción que corresponda.
index.php
< ?php
1 //Primero algunas variables de configuracion
2 require 'conexion.php';
3
4 //La carpeta donde buscaremos los controladores
5 $carpetaControladores = "controladores/";
6
7 //Si no se indica un controlador, este es el controlador que se
8 usará
9 $controladorPredefinido = "items";
10
11 //Si no se indica una accion, esta accion es la que se usará
12 $accionPredefinida = "listar";
13
14 if(! empty($_GET['controlador']))
15 $controlador = $_GET['controlador'];
16 else
17 $controlador = $controladorPredefinido;
18
19 if(! empty($_GET['accion']))
20 $accion = $_GET['accion'];
21 else
22 $accion = $accionPredefinida;
23
24 //Ya tenemos el controlador y la accion
25
26 //Formamos el nombre del fichero que contiene nuestro controlador
27 $controlador = $carpetaControladores . $controlador .
28 'Controlador.php';
29
30 //Incluimos el controlador o detenemos todo si no existe
31 if(is_file($controlador))
32 require_once $controlador;
33 else
34 die('El controlador no existe - 404 not found');
35
36 //Llamamos la accion o detenemos todo si no existe
37 if(is_callable($accion))
38 $accion();
39 else
40 die('La accion no existe - 404 not found');
?>
Y ya lo podemos probar:
index.php?controlador=items&accion=listar
¿Y si ahora quiero insertar items?
itemsControlador.php
function listar()
1 {
2 //Incluye el modelo que corresponde
3 require 'modelos/itemsModelo.php';
4
5 //Le pide al modelo todos los items
6 $items = buscarTodosLosItems($db);
7
8 //Pasa a la vista toda la información que se desea
9 representar
10 require 'vistas/listar.php';
11 }
12
13 function agregar()
14 {
15 echo 'Aqui incluiremos nuestro formulario para insertar
16 items';
17
18 require 'modelos/itemsModelo.php';
19
20 if($_POST)
21 {
22 insertar();
23 }
24
25 require 'vistas/agregar.php';
}
Desde luego que el modelo ahora también debería incluir una función insertar() y
debería existir una plantilla agregar.php. Para ver nuestro formulario solo deberiamos
ingresar por:
index.php?controlador=items&accion=agregar
Para ello, solo debes crear un controlador usuariosControlador.php con una funcion
listar() similar a la de itemsControlador, y obviamente, también debes crear las
plantillas que creas necesarias o, por que no, reutilizar alguna que ya tengas.
index.php?controlador=usuarios&accion=listar
Notas finales
Y hasta aquí llega esta primera parte. Logramos implementar un script separado en 3
capas y dimos el primer paso con MVC usando programación estructurada/funcional.
En el articulo que sigue mostraré esto mismo pero con programación orientada a objetos
y algunas funcionalidades extras como aplicar URL amigables a un sistema de este tipo.
TUTORIAL 3
Patron MVC
La forma más sencilla de implementar este patrón es pensando en capas, como regla, los
accesos a la base de datos se hacen en el modelo, la vista y el controlador no deben de
saber si se usa o no una base de datos. El controlador es el que decide que vista se debe
de imprimir y que información es la que se envía.
1
<?php
2 class AutomovilesController extends Controller {
3 public function __construct() {
4
5 }
6
7 public function listaAutomoviles() {
8 $automoviles = new Automoviles();
9
10 $data = array();
11 $data['Autos'] = $automoviles->findAll();
12
13 $view = new View();
14 $view->setData( $data );
15 $view->setTemplate( 'tpl/listado.php' );
16 $view->setLayout( 'tpl/mainLayout.php' );
17
18 $view->render();
19 }
20
21 }
22 ?>
Vista (listado.php):
1
<table class="listadoAutos">
2 <tr>
3 <th>ID</th>
4 <th>Nombre</th>
5 <th>Color</th>
6 </tr>
7 <?php foreach( $Autos as $automovil ) { ?>
8 <tr>
9 <td><?php echo $automovil['id']; ?></td>
10 <td><?php echo $automovil['nombre']; ?></td>
11 <td><?php echo $automovil['color']; ?></td>
12 </tr>
13 <?php } ?>
14 </table>
Modelo: (Automoviles.php)
1
<?php
2 class Automoviles extends ActiveTable {
3 public function __construct() {
4 parent::__construct();
5
6 $this->resultObject = "Automovil";
7 }
8 }
9
10 class Automovil extends ActiveRecord {}
11 ?>
1
<?php
2 include( 'ActiveTable.php' );
3 include( 'ActiveRecord.php' );
4 include( 'View.php' );
5 include( 'Controller.php' );
6 include( 'AutomovilesController.php' );
7 include( 'Automoviles.php' );
8
9 $controller = new AutomovilesController();
10 $controller->listaAutomoviles();
11 ?>
Como podemos ver la vista (que no es nada más que otro PHP) se encarga de imprimir
la tabla y dejarla lista para su visualización, el modelo solo recibe lo que el controlador
le envía y es de donde la vista obtiene su fuente de información.
Controlador (AutomovilesController.php):
1
<?php
2 class AutomovilesController extends Controller {
3 public function __construct() {
4
5 }
6
7 public function nuevoAuto() {
8 $data = array();
9 if( strtoupper( $_SERVER['HTTP_REQUEST_METHOD'] ) == "POS
T" ) {
10 $nombre = $_POST['nombre'];
11 $color = $_POST['color'];
12
13 $errors = array();
14 if( empty( $nombre ) ) {
15 $errors['nombre'] = "Debe de escribir un nombr
e";
16 }
17
18 if( empty( $color ) ) {
19 $errors['color'] = "Debe de seleccionar un col
or";
20 }
21
22 $noErrors = ( count( $errors ) > 0 ? false : true )
;
23
24 if( $noErrors ) {
25 $automoviles = new Automoviles();
26 $auto = $automoviles->add();
27
28 $auto['nombre'] = $nombre;
29 $auto['color'] = $color;
30
31 try {
32 $auto->save();
33 $id = $auto['id'];
34
35 $data['Mensaje'] = "Automovil $id Inserta
do exitosamente";
36 } catch( Exception $e ) {
37 $data['Mensaje'] = $e->getMessage();
38 }
39 }
40 }
41
42 $view = new View();
43 if( isset( $errors ) && !$noErrors ) {
44 $data['errors'] = $errors;
45 }
46
47 $view->setData( $data );
48 $view->setTemplate( 'tpl/nuevoAuto.php' );
49 $view->setLayout( 'tpl/mainLayout.php' );
50
51 $view->render();
52 }
53 }
54 ?>
Vista (nuevoAuto.php):
1
<?php if( !empty( $Mensaje ) ) { ?>
2 <h1>
3 <?php echo $Mensaje; ?>
4 </h1>
5 <?php } ?>
6 <form action="nuevoAuto.php" method="post">
7 <table class="nuevoAuto">
8 <tr>
9 <td>Nombre:</td>
10 <td><input type="text" name="nombre" value="" /><?
php if( !empty( $errors['nombre'] ) ) { echo $errors['nombre']; } ?
></td>
11 </tr>
12 <tr>
13 <td>Color:</td>
14 <td><input type="text" name="color" value="" /><?
php if( !empty( $errors['color'] ) ) { echo $errors['color']; } ?
></td>
15 </tr>
16 <tr>
17 <td colspan="2">
18 <input type="submit" name="agregar" value="Agr
egar" />
19 </td>
20 </tr>
21 </table>
22 </form>
1
<?php
2 include( 'ActiveTable.php' );
3 include( 'ActiveRecord.php' );
4 include( 'View.php' );
5 include( 'Controller.php' );
6 include( 'AutomovilesController.php' );
7 include( 'Automoviles.php' );
8 include( 'Automovil.php' );
9
10 $controller = new AutomovilesController();
11 $controller->nuevoAuto();
12 ?>
Este ejemplo es muy básico, y al patrón MVC se le han agregado muchas cosas, como
puede ser un Router que se encargue de decidir que controlador utilizar dependiendo de
la entrada de información.
Otra adición son los smart-urls estos se encargan de que los urls sean más amigables,
aunque esto no depende enteramente de PHP, pero es una adición que muchos ocupan a
la hora de utilizar este patrón de diseño.
Controller.php:
1
<?php
2 class ControllerException extends Exception {}
3 class Controller {
4 public function __call() {
5 throw new ControllerException('Error fatal, se llamo a un
a funcion que no esta definida');
6 }
7 }
8 ?>
View.php:
1
<?php
2 class ViewException extends Exception {}
3 class View {
4 private $data;
5 private $template;
6 private $layout;
7
8 public function __construct() {}
9
10 public function setData( $data ) {
11 if( !is_array( $data ) ) {
12 throw new ViewException('$data se esperaba fuera un
arreglo, se envio un ' . gettype( $data ));
13 }
14 $this->data = $data;
15 }
16
17 public function setLayout( $layout ) {
18 if( !file_exists( $layout ) ) {
19 throw new ViewException('$layout no es un archivo
existente');
20 }
21
22 $this->layout = $layout;
23 }
24
25 public function setTemplate($template) {
26 if( !file_exists( $template ) ) {
27 throw new ViewException('$template no es un archivo
existente');
28 }
29
30 $this->template = $template;
31 }
32
33 public function render() {
34 $content = $this->renderTemplate();
35
36 include( $this->layout );
37 }
38
39 private function renderTemplate() {
40 ob_start();
41 @extract( $this->data, EXTR_OVERWRITE );
42 include( $this->template );
43 $content = ob_get_clean();
44
45 return $content;
46 }
47 }
48 ?>
mainLayout.php:
1
<html>
2 <head>
3 <title>Sistema de Autos</title>
4 </head>
5 <body>
6 <?php echo $content; ?>
7 </body>
8 </html>
AutomovilesController.php:
1
<?php
2 class AutomovilesController extends Controller {
3 public function __construct() {
4
5 }
6
7 public function listaAutomoviles() {
8 $automoviles = new Automoviles();
9
10 $data = array();
11 $data['Autos'] = $automoviles->findAll();
12
13 $view = new View();
14 $view->setData( $data );
15 $view->setTemplate( 'tpl/listado.php' );
16 $view->setLayout( 'tpl/mainLayout.php' );
17
18 $view->render();
19 }
20
21 public function nuevoAuto() {
22 $data = array();
23 if( strtoupper( $_SERVER['HTTP_REQUEST_METHOD'] ) == "PO
ST" ) {
24 $nombre = $_POST['nombre'];
25 $color = $_POST['color'];
26
27 $errors = array();
28 if( empty( $nombre ) ) {
29 $errors['nombre'] = "Debe de escribir un nombr
e";
30 }
31
32 if( empty( $color ) ) {
33 $errors['color'] = "Debe de seleccionar un col
or";
34 }
35
36 $noErrors = ( count( $errors ) > 0 ? false : true )
;
37
38 if( $noErrors ) {
39 $automoviles = new Automoviles();
40 $auto = $automoviles->add();
41
42 $auto['nombre'] = $nombre;
43 $auto['color'] = $color;
44
45 try {
46 $auto->save();
47 $id = $auto['id'];
48
49 $data['Mensaje'] = "Automovil $id Inserta
do exitosamente";
50 } catch( Exception $e ) {
51 $data['Mensaje'] = $e->getMessage();
52 }
53 }
54 }
55
56 $view = new View();
57 if( isset( $errors ) && !$noErrors ) {
58 $data['errors'] = $errors;
59 }
60
61 $view->setData( $data );
62 $view->setTemplate( 'tpl/nuevoAuto.php' );
63 $view->setLayout( 'tpl/mainLayout.php' );
64
65 $view->render();
66 }
67 }
68 ?>
Espero les ayude a comprender mejor como se utiliza el patrón MVC y como hace que
las cosas sean más flexibles.
TUTORIAL 1....................................................................................................................1
Tutorial MVC con PHP.....................................................................................................1
¿Qué es MVC?..........................................................................................................1
¿Porqué útilizar MVC?..............................................................................................2
Utilizando el Controlador y la Vista..........................................................................2
Utilizando el Modelo.................................................................................................3
Cambiando el gestor de Base de Datos.....................................................................4
TUTORIAL 2....................................................................................................................5
TUTORIAL 3..................................................................................................................12
Patron MVC.............................................................................................................12