Ejemplo de aplicación para un Blog sobre Zend Framework - Parte 3: Tutorial para un simple Hola Mundo

sábado, 13 de septiembre de 2008


Esta es una traducción de la serie de artículos publicados en http://blog.astrumfutura.com, no representa una traducción oficial, sino un trabajo voluntario para darlo a conocer en nuestro idioma.


Es casi obligatorio cuando se llega a un nuevo tema en programación, que el autor presente el ejemplo mas simple posible. por lo general, esto significa hacer uso de un lenguaje de programación o Framework para imprimir "Hola Mundo" en la pantalla. No voy a ser diferente. Esto en cuanto a originalidad...

Anteriormente: Parte 2 - La arquitectura MVC de la aplicación


Paso 1: Creando una nueva aplicación

Antes de saltar a la programación con el Zend Framework hay algunas tareas de configuración. Necesitamos instalar el Zend Framework, obtener un dominio virtual en funcionamiento, y tener una colección básica de directorios y archivos en blanco creados para adherirse a nuestro código fuente.

Para ello necesitará descargar el Zend Framework 1.5.3 (Reciente liberación) de http://framework.zend.com y pongalo en algún lugar de su ruta de includes (inclusión). Trato de minimizar el número de rutas de includes y no acabar teniendo que escoger rutas extrañas (como el directorio PEAR que por lo general ya se encuentra en el include_path) u otra ubicación central de librerías como PEAR donde podría tener una docena de librerias reunidas.

Una solución común encontrada en Blogs y Artículos es poner el framework dentro del directorio "library" que estaría ubicado dentro del directorio "application" en el árbol de directorios. Por lo general no recomiendo esto a menos que su aplicación necesite una versión específica de Zend Framework - Una ubicación centralizada del Zend Framework para que múltiples aplicaciones puedan accederla, puede hacer el mantenimiento un poco mas fácil.

Me he decidido por usar un host virtual, principalmente porque es fácil de instalar y ayuda a evitar algunos molestos temas de rutas base que se obtienen en su HTML cuando se usa mod_rewrite para urls accesibles - especialmente en el desarrollo donde, en caso contrariom la raiz de documentos de localhost se convierte en una masa de subdirectorios sobre subdirectorios que acaban causando problemas de tipo href muy fácilmente. Por lo general abro el archivo virtual-host.conf desde el directorio conf de Apache y añado algo así:


NameVirtualHost ∗:80



<VirtualHost ∗:80>

DocumentRoot “/path/to/htdocs”

ServerName localhost

</VirtualHost>



<VirtualHost ∗:80>

ServerName zfblog

DocumentRoot “/path/to/project/trunk/public”

</VirtualHost>



Esto debería dar lugar a que todas las consultas HTTP para http://zfblog/ lleguen a la raiz de documentos seleccionado (que es el directorio público para el proyecto, que contiene a index.php, ubicado en nuestra copia de trabajo con subversion en el directorio "trunk"). Vamos a crear esta estructura de directorios mas tarde. Por lo general también necesitamos referenciar a localhost para asegurar su reconocimiento por paerte del host de forma correcta - de lo contrario cualquier direccionamiento a localhost que ya haya hecho de repente serán desviados a la raiz de documentos de zfblog misteriosamente ;-).

Para aquellos de ustedes que están Windows XP o vista, también tendrán que añadir el nuevo dominio virtual a su archivo de hosts (normalmente C:\WINNTsystem32\drivers\etc\hosts). Esto es un tanto mas dificil en Vista - Probablemente necesitará  modificar el archivo de los permisos de los archivos usando una cuenta de Administrador para garantizarle al usuario local privilegios adicionales para modificar. ¡Asegurese de revertir los privilegios después! de Editar a solo Ver.

# Copyright (c) 1993-1999 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.

127.0.0.1 localhost

127.0.0.1 zfblog

Reinicie su servidor y con un poco de suerte, verá en el navegador un listado de directorios (Una vez añada el directorio raiz "public" como se muestra mas abajo).

La parte menos interesante es la creación de un árbol de directorios para contener nuestro código fuente. Wil Sinclair a lo largo de Zend está trabajando en un componente Zend_Build que seguramente algún dia eliminará la repetición en la creación de estos directorios y archivos por defecto. Hasta entonces, dejemos seguir a la monotonia (o mantenga un esqueleto a mano para poder copiar y pegar ;-) ).

He aquí una imágen del ejemplo Hola Mundo y como se observa la vista de directorios desde Eclipse:



Copie y cree la misma estructura de durectorios en un nuevo directorio llamandolo como usted prefiera, en este caso lo llamaremos "zfblog". Si quieres poner todo en el "trunk", es opcional - Aquí he usado subversion, esa es la razón por la que existe el directorio "trunk". Si no ha llegado a usar Subversion antes, le sugiero que aprenda un poco mas de esta herramienta, es altamente recomendado su uso, además es simple de aprender y usar.

Vamos a revisar brevemente cada uno de estos directorios.

El directorio "application" es donde ubicamos todos los componentes donde una aplicación implementa el Modelo-Vista-Controlador. Dentro de "application" encontramos a , "controllers", "models" y "views" que representan las ubicaciones respectivas  para el controlador, el modelo  y la vista de código fuente y plantillas. Dentro de "Views" hay una subdivisión entre "filters", "helpers", "layouts" y "scripts". Por ahora, recuerde que nosotros ponemos todos los templates renderizados por la vista en "scripts". En la captura de pantalla, vemos un directorio index que contiene un archivo index.phtml, que es el template de la vista para indexAction de una clase IndexController. los demas los conoceremos luego.

El directorio "modules" es también para controladores, modelos y vistas, pero en este caso son categorizados dentro de múltiples divisiones de una aplicación. Si lo piensas, veras que en una aplicación pueden estar separados en varias partes, por ejemplo la aplicación principal y una parte de administración. La sección de administración podria estar separada dentro del Módulo Admin por lo tanto no está entremezclada con la aplicación principal.

Existe un archivo Bootstrap.php en el directorio "application" que representa  un clase llamada "Boostrap". Su propósito es inicializar el Zend Framework, ajustar las preferencias del entorno (por ejemplo, la zona horaria y el nivel del error_reporting), y por otro lado realiza ajustes y adiciones específicas a la aplicación antes de procesar una petición por HTTP. Muchos tutoriales usan otra alternativa de vista y ponen el código del Boostrap dentro del código de index.php. Le recomiendo evitar este método y usar una clase real para organizar el código del Bootstrap - esto hace que sea mucho mas fácil de leer ¡si no hay nada mas!.

El directorio "config" simplemente tiene los datos de configuración para la aplicación, por ejemplo, los detalles de la conexión a la base de datos.

El directorio "library" puede tener una copia del Zend Framework. Generalmente evito esto ya que es mucho mas fácil agregar el Zend Framework al include_path de PHP. pero sin embargo lo anterior es muy útil si quiere cambiar la versión del Zend Framework para un uso mas flexible. también es muy útil si lo usa para añadir un referencia svn:external al repositorio subversion del Zend Framework.

El directorio "public" tiene todos los arcivos accesibles por una petición al servidor web. este directorio incluye un archivo index.php que se ocupa de todas las peticiones de la aplicación llamando a la case Bootstrap, así como cualquier archivo CSS, HTML javascript etc...

Una nota sobre el despliegue en la práctica: en general, en el despliegue usted mueve el directorio "public" a su servidor web para que sea accesible sobre Internet, pero mantiene los directorios no públicos dentro del directorio raiz del sitio.  ya que index.php termina haciendo una simple referencia al archivo Bootstrap.php incluyendolo, significa que muchos de los archivos de la aplicación no serán accesibles por los usuarios de Internet. También significa que el archivo index.php terminará decidiendo donde está ubicado el archivo Bootstrap - por lo tanto es el único archivo que siempre necesitará ser editado a mano para el despliegue y cambiar esa ubicación según sea necesario.

El directorio "test" normalmente tiene cualquier aplicacion específica de unidad, especificación y pruebas de aceptación. Como lo dije anteriormente, estoy tomando deliberadamente un enfoque test-light para permanecer sobre el tema (Tengo mas de un articulo de prueba/desarrollo en el Zend DevZone en el caso que esté interesado en aplicar TDD o BDD). Las pruebas principales que espero tener son para las clases específicas de la aplicación: cualquier Modelo lógico por ejemplo.

Al final de este paso denería tener el directorio estructurado en un lugar conteniendo algunos archivos en blanco como los siguientes (creelos ahora, y los llenamos luego):

/application/Bootstrap.php

/application/controller/IndexController.php

/application/views/scripts/index/index.phtml

/public/index.php

/public/.htaccess


Paso 2: Implementando nuestro archivo Bootstrap.

El Bootstrapping es cuando configuramos el entorno inicial e inicalizamos el Zend Framework para nuestra aplicación. No es un archivo dificil de escribir, pero puede crecer y volverse mas complejo a medida que nuestra aplicación vaya aumentando en características. Para manejar esto es altamente recomendado implementarlo en una clase con métodos pequeños en tamaño. Para el esqueleto de nuestra aplicación Hola Mundo, /application/Bootstrap.php contiene:


require_once 'Zend/Loader.php';

class Bootstrap
{

    public static $frontController = null;
  
    public static function run()
    {
        self::setupEnvironment();
        self::prepare();
        $response = self::$frontController->dispatch();
        self::sendResponse($response);
    }
  
    public static function setupEnvironment()
    {
        error_reporting(E_ALL|E_STRICT);
        ini_set('display_errors', true);
        date_default_timezone_set('Europe/London');
    }
  
    public static function prepare()
    {
        self::setupFrontController();
        self::setupView();
    }
  
    public static function setupFrontController()
    {
        Zend_Loader::registerAutoload();
        self::$frontController = Zend_Controller_Front::getInstance();
        self::$frontController->throwExceptions();
        self::$frontController->returnResponse(true);
        self::$frontController->setControllerDirectory(
            dirname(__FILE__) . '/controllers'
        );
    }
  
    public static function setupView()
    {
        $view = new Zend_View;
        $view->setEncoding('UTF-8');
        $viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view);
        Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
    }
  
    public static function sendResponse(Zend_Controller_Response_Http $response)
    {
        $response->setHeader('Content-Type', 'text/html; charset=UTF-8', true);
        $response->sendResponse();
    }

}


La clase Bootstrap tiene dos métodos principales aquí: run() y prepare(). run() ejecuta una petición completa a la aplicación, mientras que prepare() solo establece (pero no ejecuta) el Front Controller. Por ahora enfoquemonos en run() y todos los pasos que nuestro Bootstrap realiza cuando es llamado, El método prepare() es el que uso cuando aplico TDD o BDD para el desarrollo de los controladores, ya que delega la ejecución del controlador al framework de pruebas.

Los primero es configurar el entorno local. Así que aquí hemos establecido una zona horaria (Según lo requiera PHP), habilitar  la opción display_errors de PHP.  un establecer un error bastante  rigido a nivel de información. Si poniendo lo básico dentro de una clase parece poco intuitivo, puede simplemente extraerlo a la cabecera del archivo. Y que por lo general lo pruebo bastante, normalmente no los quiero corriendo durante mis pruebas e interfiriendo con los resultados de las pruebas.

En segundo lugar, preparamos el Front Controller. Zend _Controller es una implementación del patrón de diseño Front Controller, que actua como un único punto de entrada a una aplicación de arquitectura Modelo-Vista-Controlador. Cada petición que no es para un archivo público existente para a través de él. En nuestro caso, ya que el Bootstrap esta incluido dentro y es llamado por public/index.php, "index.php" es nuestro único punto de entrada.

En este sentido, la fase de prepare() involucra la creación del Front Controller:
- Ontiene una instancia del Zend_Controller_Front
- Configurarlo para que capture todas las excepciones (Talvez quiera desactivarlo cuando se encuentre en producción).
- Configurarlo para que devuelva un objeto Response en caso de envio.
Indicarle donde encontrar los controladores por defecto.

El último paso de prepare() hace algunos cambios a la vista. La razón por la que he hecho esto es para mostrar como hacer un cambio muy común - agregando soporte para la salida codificada en UTF-8. No te preocupes demasiado por los detalles ahora - El Action Helper ViewRenderer y el Helper Broker permite añadir o modificar los Action Helpers y está bien abarcado por Matthew Weier O’Phinney en el Zend Devzone - http://devzone.zend.com/article/3350-Action-Helpers-in-Zend-Framework.

Ahora, ¿Que pasa con /public/index.php?


// Update after deployment for location of non-public files
$root = dirname(dirname(__FILE__));

// We’re assuming the Zend Framework is already on the include_path
set_include_path(
    $root . '/application' . PATH_SEPARATOR
    . $root . '/library' . PATH_SEPARATOR
    . get_include_path()
);

require_once 'Bootstrap.php';

Bootstrap::run();

En si mismo Simplicidad! El Index es nuestro único punto de entrada del Front Controller dentro de una aplicación en Zend Framework, y todo lo que necesitamos determinar es un include_path válido para la aplicación y delegar todas las tareas al método run() de la clase Bootstrap.

El paso final es el cómo hacer que todas las solicitudes de "http://zfblog/" pasen a través de index.php. Esto es solucionado por los servidores Apache usando módulo Rewrite, que simplemente toma la URL de una petición entrante y la re-escribe apuntando a index.php. Si nunca ha usado el Rewrite de Apache, probablemente necesite habilitarlo en el htttp.cond antes de que funcione. Las reglas de re-escritura pueden ser definidas en el archivo http.conf de Apache o simplemente usando un archivo .htaccess en el directorio "public" que contenga las reglas:

RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-f

RewriteRule .∗ index.php


El archivo .htaccess de aquí, primero habilita la re-escritura, y luego especifica las reglas. Las reglas de aquí mapean todas las peticiones a index.php, a menos que se refieran a un archivo que existe en el servidor (es decir, no va a reescribir la URL a CSS, Javascript o archivos de imagen).


Paso 4: Implementando el Index Controller

Antes de continuar, unas breves palabras sobre la relación Controlador/Vista. Algún tiempo atrás se decidió hacer interpretación automatizada en el modo por defecto del Zend Framework. Esto significa que el Controlador raramente necesita una intervención manual para interpretar la Vista - en vez de eso un Action Helper llamado ViewRenderer (que deberia sonar familiar ya que lo usamos para agregar la codificación UTF-8 en nuestro Bootstrap)es llamado. Este Helper localiza una vista que coincida con el nombre del controlador y acción actual, automáticamente lo interpreta. Existen distintas maneras de desactivar esta interpretación automatizada tal como se documenta en el manual - que a menudo es útil cuando se quiere eludir al Zend_View.

Si la URL de una solicitud enviada a la aplicación en Zend Framework no contiene un controlador o acción de referencia, el Zend Framework usa el valor por defecto "index". Puesto que sólo intentamos hacer solicitud a la raiz del URL "hhtp://zfblog", necesitaremos un IndexController que contenga un Index Action. ¡Vamos a crear una!.

Agregue un archivo llamado "IndexController.php" en application/controllers conteniendo:



class IndexController extends Zend_Controller_Action
{
   
    public function indexAction()
    {
        $this->view->title = 'Hola, Mundo!';
    }
   
}


Todos los controladores deben extender de Zend_Controller_Action, ya que contiene todas las referencias internas a métodos y propiedades comunes a todos los controladores. Si necesita ajustar el controllador básico para agregar nuevos métodos o propiedades puede hacerlo utilizando una subclase de Zend_Controller_Action y luego hacer que todos los controladores de la aplicación extiendan de esta subclase en lugar de la original. Tenga mucho cuidado sin embargo al ahcer subclases de esta forma - es útil para añadir nuevas propiedades a la clase, pero otros métodos adicionales a menudo es mejor añadirlos como Action Helpers discretos.

Nuestro nuevo método Action hace caso omiso de la presentación; se  hace automáticamente tal como se describe anteriormente. Todo lo que necesitamos es establecer la vista de datos que necesitamos. Puede añadir casi cualquier cosa a la vista, ya que convierte una propiedad en una Vista de plantilla. Por lo tanto, sientase libre de añadir objetos y matrices. Si se utiliza Smaty o PHPTAL, esto podría ser diferente.

Arriba dijimos que la Vista en los templates podría referirse a una variabel título y darle un valor de "Hola, Mundo". Una vez que el método de acción se realiza, el ViewRenderer lo lanza e intenta interpretar un template ubicado en '/ruta/a/la/aplicacion/views/scripts/index/index.phtml'.

¿Y que es el uso de un controlador sin una Vista para desplegar?


Paso5: Implementando la vista para indexController::indexAction()

Por defecto, el Zend Framework o mas específicamente el ViewRenderer Action Helper, tratará de interpretar un plantilla para todos los Action Controller usando una convención simple, Por ejemplo, la plantilla para IndexController::indexAction() debería estar ubicada en ""/index/index.phptml" dentro del subdirectorio "scripts" de "views".

El componente Zend_View es reponsable de interpretar todas las palntillas de la vista, a menudo con un poco de ayuda (Ejemplo: ViewRenderer o Zend_Layout) desde el controlador. Una plantilla de Zend_View es HTML (o algún otro tipo de salida) intercalados con PHP y no se utiliza un lenguaje separado de etiquetas como el motor de plantillas Smarty.. Aquí hay algo para poner dentro de su archivo index.phtml para nuestra primera aplicación en Zend Framework.



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>

    <meta http-equiv="Content-Type" content="text/html; charset="utf-8″ />

    <meta name="language" content="en" />

    <title><?php echo $this->escape($this->title) ?></title>

</head>

<body>

    <p>Hola, Mundo!</p>

</body>

</html>


Como puede ver, es casi puro HTML con solo PHP para la inclusión de títulos de texto (Que fijamos desde nuestro anterior método indexAction()). Para garantizar la seguridad contrar Cross Site Scripting (XSS) debemos escapar todas las salidas desde dentro de la aplicación, y Zend_View usa la función de php htmlspecialchars() desde su método Zend_View::escape(). otra meción es que, ya que configuramos nuestra Vista para usar codificación UTF-8, esta codificación también es pasada dentro de htmlspecialchars().

Si se utiliza escape() por todas partes, suena mal - bien, así es, y no lo es. Es un dolor de cabeza ya que es algo que obviamente podría beneficiarse desde la automatización - porl o tanto no aplicar el escape es la excepción por defecto. Por otra parte, debe hacerse en todo momento por lo que si ve una variable haciendo echo y que no esté rodeada por el método escape() debería proceder con cuidado.


Paso 6: Funciona?

Vaya y abra el navegador, la URL base de http://zfblog/ ahora deberia retornar un documento HTML conteniendo "Hola. mundo!"


Conclusión

Obtuvimos un ejemplo simple, corriendo y funcionando qie nos proporcionó algunos conocimientos. Pero no baje la guardia todavía. Al igual que cualquier plan de batalla, no va a sobrevivir el primer contacto con el enemigo (El Blog de Maugrim Marvellous es demasiado malo ;-) ). A medida que avancemos, es mas que probable que en contremos algunos erores a nuestro enfoque, y nuestro Bootstrap necesitará expandirse para ser mas mantenible y ni siquiera hemos estudiado Zend_Db todavía!.

Es un comienzo, si tiene suerte, pueden ser muchos incios ya que puede reutilizar un esqueleto básico similiar para saltarse toda esta tarea configuración para otros poryectos en Zend Framework.

Nota: el código fuente para esta entrada está disponible para navegar o hacer un checkout con subversion, desde http://svn.astrumfutura.org/zfblog/tags/Part3. El cçodigo compelto para la aplicación completa (tal como existe hasta el momento) se encuentra en http://svn.astrumfutura.org/zfblog.

0 comentarios: