Posts almacenados bajo 'Patrones y Antipatrones'

Construcción de un sistema MVC simple con PHP5 :: Parte III

El Modelo
La ‘M’ de los sistemas MVC se refiere al modelo, es responsable de ejecutar consultas a la base de datos (u otra fuente externa como pueden ser archivos xml, csv, etc.) y proveer los datos al controlador. Nosotros debe cargar el modelo apropiado dependiendo de la solicitud de nuestro cliente, algunas personas prefieren no utilizar una clase modelo y utilizar en el controlador una librería que haga la abstracción de la BDD, como por ejemplo AdoDB, sin embargo el modelo también puede hacer uso de esta librería o utilizar las funciones nativas de php directamente. Todo depende del tamaño de la aplicación y lo práctico que resulte en la solución que propongamos

Algo que debemos hacer es agregar el código necesario para inicializar una conexión con la base de datos, y añadirlo a nuestra pagina inicial (index). Existe varias librerías de abstracción de la BDD disponibles, pero PHP5 ya viene con una gran librería PDO, entonces es posible que no necesitemos alguna más.

Ahora, colocamos el siguiente código en el archivo index (luego de incluir el archivo de inicialización):

# Conexión con la BDD
$db = new PDO(’mysql:host=localhost;dbname=demo’, ‘[usuario]’, ‘[clave]’);
$registry->set (’db’, $db);

En el ejemplo anterior primero creamos una nueva instancia de la libreria PDO, y nos conectamos a nuestra base de datos MySQL. Posteriormente hace global la conexión mediante nuestra clase Registry.

La parte del modelo de nuestro sistema, esta terminada, por lo que vamos a pasar con con la siguiente parte: codificar el controlador.
Codificar el controlador también significa que nosotros debemos codificar la clase Router. Una clase Router es responsable de cargar correctamente el controlador, basada en las solicitudes (la variable $router pasada a través de la URL). Entonces vamos a codificar la clase Router primero.

La clase Router
Nuestra clase Router deberá analizar la solicitud del cliente y cargar el comando correcto. El primer paso es crear el esqueleto básico de la clase Router:

Class Router
{
private $registry;
private $path;
private $args = array();

function __construct($registry) {
$this->registry = $registry;
}
}

Y agregamos las siguiente líneas al archive index.php:

# Carga el router
$router = new Router($registry);
$registry->set (’router’, $router);

Ahora hemos añadido la clase Router a nuestro sistema MVC, pero esta no hace nada aún, entonces debemos agregar varios métodos a nuestra clase.
El primer metodo que debemos agregar es setPath(), el cual es utilizado para definir el directorio donde se almacenan todos nuestros controladores. El metodo setPath() es similar al siguiente y require ser agregado a la clase Router:

function setPath($path)
{
$path = trim($path, '/\\');
$path .= DIRSEP;
if (is_dir($path) == false) {
throw new Exception ('Path Invalido: `' . $path . '`');
}
$this->path = $path;
}

Nota: Si su sistema no tiene la constante DIRSEP, prueben con DIRECTORY_SEPARATOR

Luego, agregamos la siguiente línea en el archivo index.php:

$router->setPath (site_path . 'controllers');

Ahora nosotros ya tenemos definido el path a nuestros controladores, entonces podemos escribir el método responsable de cargar el controlador correcto. Este método es llamado delegate(). Una primera versión de este método puede ser como sigue:

function delegate()
{
// Obtiene el controlador
$this->getController($file, $controller, $action, $args);

Como pueden ver, hace uso de otro método, getController() para obtener el controlador. Este método sería algo así:

private function getController(&$file, &$controller, &$action, &$args)
{
$route = (empty($_GET['route'])) ? '' : $_GET['route'];
if (empty($route)) { $route = 'index'; }
// Separa las partes
$route = trim($route, '/\\');
$parts = explode('/', $route);
// Busca el controlador correcto
$cmd_path = $this->path;
foreach ($parts as $part) {
$fullpath = $cmd_path . $part;

// Existe un directorio con el path completo?
if (is_dir($fullpath)) {
$cmd_path .= $part . DIRSEP;
array_shift($parts);
continue;
}
// Busca el archivo
if (is_file($fullpath . '.php')) {
$controller = $part;
array_shift($parts);
break;
}
}
if (empty($controller)) { $controller = 'index'; };
// Obtiene la accion
$action = array_shift($parts);
if (empty($action)) { $action = 'index'; }
$file = $cmd_path . $controller . '.php';
$args = $parts;
}

Veamos un poco el funcionamiento de este método. Primero obtiene el valor de la variable $route y procede a separarla en partes, utilizando la función explode(). Si la solicitud es ‘miembro/ver’ esto debería dividirlo en un arreglo: array(’miembro’, ‘ver’).

Podemos utilizar el loop foreach para recorrer cada parte y primero chequear si cada parte es un directorio. Si lo es, lo agregamos en el filepath y nos movemos a la siguiente parte. Esto permite poner al controlador en subdirectorios, y utilizar jerarquía en los controladores. Si una parte no es un directorio pero es un archivo, almacenamos esto en la variable $controller, y salimos del loop por que hemos encontrado el controlador que queríamos.

Luego del loop nos aseguramos que el controlador ha sido encontrado, y si no existe un controlador ponemos por omisión a uno llamado ‘index’.
Procedemos a obtener la acción que deseamos ejecutar. El controlador es una clase que se compone de varios métodos, y las acciones apuntan a uno de estos métodos. Si no se especifica una accione llamaremos a una acción llamada ‘index’.

Finalmente, obtenemos el path complete del archive controlador concatenando el path con el nombre del controlador y su extensión.

Ahora que la solicitud ha sido analizada se la envía al método delegate() para cargar el controlador y ejecutar la acción. El método delegate() complete sería algo así::

function delegate()
{
// Analiza la ruta
$this->getController($file, $controller, $action, $args);
// El archivo existe?
if (is_readable($file) == false) {
die ('404 Not Found');
}
// Incluye el archivo
include ($file);
// Inicializa la clase
$class = 'Controller_' . $controller;
$controller = new $class($this->registry);
// Existe la Accion?
if (is_callable(array($controller, $action)) == false) {
die ('404 Not Found');
}
// Ejecuta la acción
$controller->$action();
}

Luego de tener analizada la solicitud con el metodo getController(), primero debemos asegurarnos que el archivo existe y si no retornar un sencillo mensaje de error.

La siguiente cosa que debemos hacer es incluir el archivo controlador, e inicializar la clase, que siempre debe ser llamada Controller_[nombre]. Luego aprenderemos mas sobre el controlador.

Entonces verificamos si la acción existe y es ejecutable utilizando is_callable(). Finalmente, ejecutamos la acción, que completa el rol del router.

Ahora que tenemos funcionando completamente el método delegate(), agregamos las siguientes líneas al archivo index.php:
$router->delegate();

Si intentan ejecutar el archivo ahora, obtendremos el siguiente error por que no tenemos creado el directorio ‘controllers’:

Fatal error: Uncaught exception 'Exception' with message 'Invalid controller path: `g:\Projects\PHPit\content\simple mvc php5\demo\controllers\`' in g:\Projects\PHPit\content\simple mvc php5\demo\classes\router.php:18 Stack trace: #0 g:\Projects\PHPit\content\simple mvc php5\demo\index.php(13): Router->setPath('g:\Projects\PHP...') #1 {main} thrown in g:\Projects\PHPit\content\simple mvc php5\demo\classes\router.php on line 18

O obtendremos ‘404 Not Found’ porque no tenemos controladores creados aun. Pero ese es el tema de la siguiente parte de este tutorial.

Añadir comentario Junio 06, 2008

Construcción de un sistema MVC simple con PHP5

El siguiente post corresponde a una traducción del articulo Building a simple MVC system with PHP5 (http://www.phpit.net/article/simple-mvc-php5/) por lo que el crédito lo dejo a sus respectivos autores. Únicamente me parece buena idea incrementar la información existente en Internet sobre programación y diseño en PHP en aspectos diferentes al estilo de programación estructurada.

Continue leyendo Añadir comentario Abril 22, 2008

Construcción de un sistema MVC simple con PHP5 :: Parte II

Tareas de inicialización

Las tareas de inicialización son utilizadas para realizar tareas generales de inicialización como definir constantes, configurar el nivel de reporte de errores, etc. La primera parte del archivo de inicialización debe verse de cómo lo esto:

Continue leyendo 5 comentarios Febrero 26, 2007

Construcción de un sistema MVC simple con PHP5

El siguiente post corresponde a una traducción del articulo Building a simple MVC system with PHP5 (http://www.phpit.net/article/simple-mvc-php5/) por lo que el crédito lo dejo a sus respectivos autores. Únicamente me parece buena idea incrementar la información existente en Internet sobre programación y diseño en PHP en aspectos diferentes al estilo de programación estructurada.

Resumen

En este tutorial usted va a aprender como construir un sistema Modelo-Vista-Controlador simple con PHP 5.1 y algunas de las características de la Biblioteca Estándar de PHP (SPL’s).

Continue leyendo Añadir comentario Febrero 18, 2007

Antipatron Metodológico – Reinventar la Rueda

Empezando con la promesa de publicar una serie de post sobre patrones y antipatrones he decidido iniciar con “Reinventar la rueda” o en ingles “Reinvent the Wheel”. Para empezar se debe especificar que se trata de un antipatron metodológico que básicamente consiste en ignorar una solución probada y garantizada para desarrollar una solución propia con el fin de resolver un problema dado y que a la final resulta en la misma solución. Resumidamente es el “Esfuerzo ya realizado por otros pero desconocido para nosotros”

Continue leyendo 1 comentario Febrero 12, 2007

¿Que son los patrones y antipatrones?

Antes de iniciar una serie de post sobre los patrones y antipatrones de diseño, vale la pena aclarar que son los Patrones y Antipatrones de diseño.

Básicamente los patrones de diseño son soluciones a problemas de diseño no trivial que se producen comúnmente en temas relacionados con el desarrollo de software, algunos ejemplos pueden ser los patrones creacionales y de comportamiento. Por otro lado un antipatron es un patron de diseño que llevará a una mala solución de un problema, en realidad es lo que no deberíamos hacer o lo que debemos tratar de evitar hacer siempre que sea posible….

Debido a que ultimamente me encuentro trabajando bastante sobre PHP trataré en lo posible de aplicar los conceptos expuestos a este lenguaje de programación (especialmente en POO)

Añadir comentario Febrero 04, 2007



Posts por mes

Posts por categoria