Del 1-12-2007 al 15-12-2007 juaxix zenphp :: Proyecto alojado en la Forja de Rediris http://blog.zenphp.es Abstract Aprendiendo zenphp! Construyendo un sistema MVC simple con PHP y zenphp En ste breve tutorial aprenders cmo se construye un modelo de datos con el subsistema Modelo/Visualizador/Controlador de zenphp gracias a la ayuda de libreras estndar de PHP y las caractersticas de zenphp. Introduccin Bienvenid@ al primer tutorial de construccin de aplicaciones con MVC de zenphp, es necesario que en tu servidor dispongas de la Standard PHP Library, tiene ms ayuda disponible aqu. A partir de aqu estamos siguiendo una serie de pasos desde 0 necesarios para un sistema completo pero sencillo de entender y construir. La entrada Un punto importante a tener en cuenta es que el sistema comienza siempre en el mismo sitio, desde donde se dirige a la parte del mismo que ha de tomar el control, lgico, no? Para que sta idea funcione hemos de decirle al servidor Apache que nos lleve al punto inicial desde donde queremos mantener el orden, para ello necesitamos establecer ciertas reglas de redireccin y que se escriben en el fichero .htaccess del directorio raz de la aplicacin : /htdocs/aplicaciones/aplicacin,
Esto es precisamente lo que se hace en Django al establecer las reglas dentro de route.py
Primero comprobamos si existe el comando RewriteCond,ya que si no existe redireccionaremos desde el fichero index.php.Sin embargo se ha de comprobar adems si existe el fichero para poder seguir redireccionando imgenes y otros ficheros. Si no podemos usar .htaccess o mod_rewrite, tendremos que realizar las peticiones de redireccin manualmentemediante una clase, zen_enrutador, lo que quiere decir que todos los enlaces deben de estar en la forma "index.php?ruta=[la-peticion-aqui]", e.j. index.php?ruta=productos/indice. Cmo funciona en Apache?
Conclusiones: no siempre podremos utilizar las redirecciones en Apache por motivos de seguridad del servidor ,por lo tanto podemos construir nuestras aplicaciones manteniendo toda la lgica del programa pero haciendo un pequeo cambio en la llamada a la clase que enruta todas nuestras direcciones al punto inicial, en lugar de utilizar directorio/aplicacin/mdulo_o_componente utilizaremos un simple cambio: directorio/index.php/aplicacin/mdulo_o_componente De forma que el zen_enrutador se da cuenta de dnde vienen las direcciones virtuales para realizar correctamente las llamadas a las partes de la aplicacin del usuario. Nota: tomaremos como directorio principal /ejemplo/
PHP para seres humanos
3 z e n p h p
: :
P r o y e c t o
a l o j a d o
e n
l a
F o r j a
d e
R e d i r i s . e s
/ /
w w w . z e n p h p . e s
Veamos,a grandes rasgos,qu es lo que necesitamos: programas:/ejemplo/index.php, /ejemplo/clases/clase_ejemplo.php, plantillas en: /ejemplo/plantillas/html y /ejemplo/css (ver ms abajo con la creacin de las 3 plantillas HTML)
clase_ejemplo.php
Entrada/Salida de la aplicacin /ejemplo/index.php
clase_ejemplo que contiene el conjunto MVC Plantillas.html
Plantillas.xml Plantillas.xslt
Plantillas.css
PHP para seres humanos
4 z e n p h p
: :
P r o y e c t o
a l o j a d o
e n
l a
F o r j a
d e
R e d i r i s . e s
/ /
w w w . z e n p h p . e s
Ahora que tenemos todas las peticiones funcionando y conocemos el esquema del flujo de informacin desde un nico punto de entrada podemos empezar a escribir el fichero index.php. Pero primero vamos con unas tareas iniciales,como crear los directorios de aplicaciones y clases,as como de contenidos. En media es donde colocamos las imgenes ,plantillas,css,idiomas, etc. Y si tenemos un administrador, hacemos lo propio ya que son aplicaciones distintas,pero en un subdirectorio admin.
Organizamos la estructura para que quede como en la captura fcil, no? :
Lista de directorios y subdirectorios de la captura: /ejemplo - + admin clases media index.php - + aplicaciones - + clases clase_ejemplo.php - + media plantillas es - + zenphp - index.php Se marca en negrita lo que vamos a construir a continuacinDe forma que creamos un primer fichero llamado index.php en /ejemplo/index.php con el siguiente contenido: <?php # Tareas de inicializacin (cargar el sistema, etc) require('zen.php'); //Carga las clases,configuraciones y funciones //fundamentales #espacio para aadir la instancia de la clase_ejemplo a continuacin ?>
PHP para seres humanos
5 z e n p h p
: :
P r o y e c t o
a l o j a d o
e n
l a
F o r j a
d e
R e d i r i s . e s
/ /
w w w . z e n p h p . e s
El fichero zen.php realiza todas tareas de inicializacin general, esto es :la definicin de constantes, (todas las de zenphp empiezan por ZF_) ,establecer el nivel de control de errores dependiendo de si estamos en modo depuracin o no,cargando funciones y clases generales ( todas empiezan por zen_ ), etc.
Lo siguiente que debemos hacer es crear la clase_ejemplo para almacenarla en /ejemplo/clases/clase_ejemplo.php e instanciarla dentro de /ejemplo/index.php. En zenphp se intentan abolir el uso de variables globales y toda la informacin fluye a travs de un sistema de padres e hijos como en Java ,el sistema MVC est basado en esta teoria,y se usa para transportar los datos a travs del sistema sin tener que usar $GLOBALS. El manual sobre usar variables globales en PHP es recomendado en este momento. La clase ms importante es el modelo de datos ( zen_modelo_datos ) ya que es la que conecta los 3 objetos que forman el MVC, para utilizarla creamos una clase que contendr el acceso a una o varias tablas de la base de datos de forma que en una sla variable disponemos del acceso al modelo, el visualizador y el controlador. /ejemplo/clases/clase_ejemplo.php: <?php Class ejemplo extends zen_modelo_datos { /** * Aplicacin a la que se vincula el modelo de datos obligatoriamente * @var zen */ var $padre; //Todo: modelo de datos est asociado a una aplicacin /** * Constructor :: MVC->Modelo , necesita una aplicacin padre * Devuelve un modelo de datos * * @param zen $_padre * @return ejemplo */ function ejemplo(&$_padre){ /* Ahora tenemos que llamar al constructor de la clase que heredamos que tiene el formato siguiente : zen_modelo_datos($padre,$campos,$tablas,$hijo,$condiciones_where); campos son los campos de las tablas, hijo es la subclase de esta si existiera condiciones_where sirve para limitar los datos mediante instrucciones where en sintaxis SQL, ejemplo : "where ide=1".
Notas: $padre es un tipo zen; $hijo y $condiciones_where son opcionales */ parent:: zen_modelo_datos($this,"ide,titulo,texto,fecha,imagen,fichero" ,"ejemplos",null,""); #ESPACIO RESERVADO PARA INICIALIZAR EL CONTROLADOR PROPIO } } //fin de la clase ejemplo en /ejemplo/clases/clase_ejemplo.php ?>
Puedes aprovechar este momento para echarle un vistazo al contenido de zen.php
PHP para seres humanos
6 z e n p h p
: :
P r o y e c t o
a l o j a d o
e n
l a
F o r j a
d e
R e d i r i s . e s
/ /
w w w . z e n p h p . e s
Hecho esto ya disponemos de un modelo de datos listo para usar, pero antes necesitamos la tabla de donde extraer los datos: Para la tabla ejemplos podemos utilizar la siguiente consulta SQL: CREATE TABLE `ejemplos` ( `ide` INT NOT NULL AUTO_INCREMENT , `titulo` VARCHAR( 250 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL , `texto` TEXT CHARACTER SET utf8 COLLATE utf8_bin, `fecha` DATE NOT NULL , `imagen` VARCHAR( 150 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL , `fichero` VARCHAR( 150 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL , PRIMARY KEY ( `ida` ) ) TYPE = MYISAM CHARACTER SET utf8 COLLATE utf8_bin; Podeis utilizar PHPMyAdmin o bien usar una lnea para ello desde php: <?php zen_basedatos:: crear_tabla ('`ejemplos` ( `ide` INT NOT NULL AUTO_INCREMENT , `titulo` VARCHAR( 250 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL , `texto` TEXT CHARACTER SET utf8 COLLATE utf8_bin, `fecha` DATE NOT NULL , `imagen` VARCHAR( 150 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL , `fichero` VARCHAR( 150 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL , PRIMARY KEY ( `ida` ) ) TYPE = MYISAM CHARACTER SET utf8 COLLATE utf8_bin;'); ?> Ahora que hemos creado la clase alojada en /clases/clase_ejemplo.php , podemos completar el cdigo inicial de /ejemplos/index.php reemplazando el comentario #espacio para aadir la instancia de la clase_ejemplo a continuacin Por : $zen =& new zen(); //Crea una aplicacin donde alojar el modelo de datos zen___carga_clase('ejemplo'); //Carga la clase ejemplo para poder instanciarla $zen->ejemplo =& new ejemplo($zen); //Asocia el padre como la aplicacin principal //Si se quiere se puede aadir una condicin a asegurar de la forma assert(is_a($zen->ejemplo,'ejemplo')); //Ya tenemos la clase instanciada,el modelo se carga automticamente con el // visualizador y el controlador por defecto,ahora podemos empezar con el // contenido: $contenido = array(); //Contenido dinmico a mostrar $contenido['titulo'] = "Listado de ejemplo"; #espacio para insertar el contenido procesado por el controlador
Ahora la variable $zen->ejemplo tiene todo lo necesario para operar con los datos, gestionar las entradas y salidas as como mostrar las salida estndar con HTML. Vamos a usar PHPMyAdmin para insertar una tupla de ejemplo ya que el administrador interno de la web no nos interesa en este momento. Para mostrar dicha tupla crearemos una plantilla simple que utilizaremos desde el visualizador dentro de la clase_ejemplo::zen_html_modelo_datos, a la que accedemos en nuestro ejemplo desde $zen->ejemplo->html
PHP para seres humanos
7 z e n p h p
: :
P r o y e c t o
a l o j a d o
e n
l a
F o r j a
d e
R e d i r i s . e s
/ /
w w w . z e n p h p . e s
El cdigo para mostrar los datos de todas las tuplas que hayamos insertado desde PHPMyAdmin en la tabla ejemplos de la base de datos mySQL es el siguiente: /ejemplo/media/plantillas/es/base_web.html <html> <head> <title>#titulo# - Página de ejemplo</title> </head> <body> #contenido# </body> </html> Informacin: el contenido entre almohadillas # son las etiquetas que se reemplazarn mediante la clase zen_plantilla. En la plantilla colocaremos las etiquetas desde index.php, #contenido# se reemplazar por: /ejemplo/media/plantillas/es/ejemplo.html <table> <thead> <th>IDE</th> <th>Título</th> <th>Texto</th> <th>Fecha</th> <th>Imagen</th> <th>Fichero</th> </thead> <tbody> #listado_ejemplos# </tbody> </table> En esta plantilla colocaremos en la etiqueta #listado_ejemplos# la siguiente informacin procesada por el visualizador del modelo de datos asociado,i.e.,una repeticin de la siguiente plantilla (procesada: reemplazando los campos) por cada tupla de la tabla ejemplos: /ejemplo/media/plantillas/es/listado_ejemplos.html <tr> <td><b>#ide#</b></td> <td><input type="text" value="#titulo#"></td> <td><textarea rows=3 cols=6>#texto#</textarea></td> <td>#fecha#</td> <td><img src="/media/img/#imagen#></td> <td><a href="/media/ficheros/#fichero#" target="_blank">#fichero#</a> </td> </tr>
Nota : el directorio /media/plantillas/es/ significa que se usa el idioma espaol
PHP para seres humanos
8 z e n p h p
: :
P r o y e c t o
a l o j a d o
e n
l a
F o r j a
d e
R e d i r i s . e s
/ /
w w w . z e n p h p . e s
Procesando los datos: Ya estamos en condiciones de ver el cdigo de /ejemplo/index.php para que la clase ejemplo instanciada como $zen->ejemplo nos haga todo el trabajo interno Cambiamos el contenido del comentario de /ejemplo/index.php : #espacio para insertar el contenido procesado por el controlador Por : //El formato de la llamada a la funcin de listado del visualizador es: //listado($fichero,$fichero_base,$marca_base,$reemplazos_base,$reemplazos_d atos) //para nuestro ejemplo slo utilizaremos los 3 primeros parmetros $contenido['contenido'] = $zen->ejemplo->controlador->procesar($_REQUEST); //Solo queda mostrar el contenido por pantalla: $zen->html->mostrar($contenido,'base_web.html');
Para que la funcin procesar del controlador del modelo de datos haga lo que nosotros necesitamos ,esto es: que por defecto muestre un listado de tuplas ,aadiremos una clase , que ser la que realice las tareas del controlador , en /ejemplo/clases/clase_controlador_ejemplo.php <?php Class controlador_ejemplo extends zen_controlador_modelo_datos { //constructor function controlador_ejemplo(&$_padre){ //Recordar siempre llamar al constructor de la clase que hereda: parent::zen_controlador_modelo_datos($_padre); } //Nuestra funcion procesar sobrecargada de la que se hereda del padre function procesar(&$datos){ return $this->padre->html-> listado('listado_ejemplos.html','ejemplo.html','listado_ejemplos'); } } ?>
Bsicamente lo que hace es llamar al visualizador y decirle que cargue los datos del modelo de datos reemplazando el contenido de las plantillas usando listado_ejemplos.html para ir mostrando todas las filas de tuplas,reemplazando las etiquetas de los campos,sobre la tabla HTML.
PHP para seres humanos
9 z e n p h p
: :
P r o y e c t o
a l o j a d o
e n
l a
F o r j a
d e
R e d i r i s . e s
/ /
w w w . z e n p h p . e s
Tenemos la clase del controlador, slo necesitamos cargarla en nuestra clase ejemplo, para ello vamos al cdigo que habamos escrito al principio y reemplazamos, de /ejemplo/clases/clase_ejemplo.php la cadena #ESPACIO RESERVADO PARA INICIALIZAR EL CONTROLADOR PROPIO Por //Necesitamos cargar la clase controlador de disco zen___carga_clase('controlador_ejemplo'); //Ahora reemplazamos, haciendo sobrecarga sobre el puntero : $this->controlador =& new controlador_ejemplo($this);
En este punto slo nos queda correr la aplicacin y comprobar que todo est funcionando correctamente, para ello vamos al navegador y escribimos la ruta http://servidor/ejemplo/
www.zenphp.es zenphp :: Proyecto alojado en la Forja de Rediris