martes, 11 de febrero de 2014

Estableciendo skins para nuestro portal

Como he comentado anteriormente la utilización de plantillas (skins) para nuestro portal agiliza enormemente el desarrollo de nuestra aplicación, dado que focalizamos nuestros esfuerzos en el ámbito de la programación o en el del diseño del portal.

Vamos a dotar a nuestro portal de soporte para plantillas (skins), para ello crearemos en la carpeta public la subcarpeta skins. Dentro de skins la carpeta con nuestra plantilla, en nuestro caso la llamaremos liquid.  Dentro de la misma las subcarpetas css e images.
El árbol de directorios queda:
/ public
  / skins
    / liquid
      / css
      / images

Es momento de mover el fichero antes creado public/css/layout.css a public/skins/liquid/css/layout.css, como todas las imágenes que pudiéramos tener de public/images a public/skins/liquid/images.
Crearemos un fichero xml en la raíz de nuestro skin con todos las hojas de estilo necesarias. Así pues creamos el fichero public/skins/liquid/skin.xml.

Contenido de public/skins/liquid/skin.xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<skin>
  <stylesheets>
    <stylesheet>layout.css</stylesheet>
    <stylesheet>text.css</stylesheet>
  </stylesheets>
</skin>

Crearemos una hoja de estilo para los textos, al igual que layout.css la ubicaremos en public/skins/liquid/css y tendrá como nombre text.css.

@CHARSET "ISO-8859-1";
body {
  font-family:Helvetica, Arial, sans-serif;
}

Nota: Ahora la referencia de nuestras imágenes debe ser relativa al path del skin, por lo tanto no olvidar renombrar la única imagen que tenemos en nuestro css:
Actualizar el fichero public/skins/liquid/css/layout.css:

#content-container {
 float: left;
 width: 100%;
 background: #FFF url(/skins/liquid/images/layout-two-liquid-background.gif) repeat-y 68% 0;
}

En Zend Framework surge la necesidad de la reutilización del código, para ayudarnos Zend Framework pone a nuestra disposición las "View Helpers", que son clases que extienden de Zend_View_Helper_Abstract y nos permiten invocar a los métodos de estas clases desde diferentes lugares de la aplicación.
Las "View Helper" van ubicadas en el directorio application/views/helpers, allí crearemos nuestra "View Helper" llamada LoadSkin.php.

Contenido de application/views/helpers/LoadSkin.php:
<?php
/**
 * Este "helper" cargará las hojas de estilos de nuestro skin
 *
 */
class Zend_View_Helper_LoadSkin extends Zend_View_Helper_Abstract
{
 public function loadSkin ($skin)
 {
  // Leemos del fichero de configuración xml las hojas he iteramos entre ellas
  $skinData = new Zend_Config_Xml('./skins/' . $skin . '/skin.xml');  
  $stylesheets = $skinData->stylesheets->stylesheet;
  // La documentación de Zend_Config_Xml indica que los datos leídos se retornarán
  // como strings, en el caso de haber un solo elemento retornaría un string. 
  // http://framework.zend.com/manual/1.12/en/zend.config.adapters.xml.html
  if($stylesheets instanceof Zend_Config)
   $stylesheetsArray = $stylesheets->toArray();
  else
   $stylesheetsArray = array($stylesheets);
  // Iteramos entre los diferentes elementos
  if (is_array($stylesheetsArray)) {
   foreach ($stylesheetsArray as $stylesheet) {
    $this->view->headLink()->appendStylesheet('/skins/' . $skin .
      '/css/' . $stylesheet);
   }
  }
 }
}

Es necesario pasarle al "View Helper" una plantilla (skin) válida, podemos usar muchos métodos pero de momento una forma rápida de inicializar el sistema de plantillas es establecer el entorno desde la clase Bootstrap, para ello añadiremos un método nuevo llamado _initview:
Contenido del fichero application/Bootstrap.php:
<?php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
 protected function _initView()
 {
  // Initialize view
  $view = new Zend_View();
  $view->doctype('XHTML1_STRICT');
  $view->headTitle('Centro de Documentación');
  $view->skin = 'liquid';
  // Add it to the ViewRenderer
  $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper(
    'ViewRenderer'
  );
  $viewRenderer->setView($view);
  // Return it, so that it can be stored by the bootstrap
  return $view;
 }
}

Ahora que ya hemos inicializado las vistas con nuestra plantilla, solo nos falta invocarla en el layout: Meta del head del fichero application/layouts/scripts/layout.phtml:

<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<?php
$this->loadSkin($this->skin);
echo $this->headMeta();
echo $this->headTitle ();
echo $this->headScript (); 
echo $this->headLink ();
?>
</head>

Podemos ver el resultado navegando en http://localhost:


Realmente no veremos muchos cambios, si acaso la tipografía ya que hemos incluido un estilo específico para la misma.
Nota: Como detalle observaremos que el título de la página no se muestra. Esto es debido a la codificación UTF-8, si en lugar de  $view->headTitle('Centro de Documentación'); fuera  $view->headTitle('Centro de Documentacion'); el título sí se mostraría. Más adelante veremos como solucionar este problema.


Diseñando nuestro portal

El diseño puede llegar a ser fustrante sobretodo cuando todos los esfuerzos se centran en la programación. En mi opinión es preferible separar ambos mundos: la programación y el diseño. Es común tener una apariencia estándar del portal, para ello el uso de plantillas (skins) nos permitirá separar la representación de la lógica de la aplicación.
Primero definiremos un esqueleto genérico para nuestro portal, en nuestro caso un patrón de dos columnas con cabecera y pie, y una sección destinada a un menú rápido. He tomado como ejemplo las múltiples plantillas gratuitas que circulan por Internet, concretamente la usada aquí puede encontrarse en http://www.maxdesign.com.au/articles/css-layouts/two-liquid/

Seguiremos los siguientes pasos:
  • Header: Cabecera del portal, logo, motor de búsqueda, etc.
  • Navigation: Menú de acceso rápido.
  • Aside: Menú lateral de usuario.
  • Main Content: Contenido del portal.
  • Footer: Pie del portal, contacto, copyright, etc.
Para ello:
  1. Crearemos una carpeta nueva en el directorio application llamada layouts.
  2. En la nueva carpeta creada añadiremos una subcarpeta llamada scripts.
  3. Crearemos el fichero layout.phtml en application/layouts/scripts.
  4. Crearemos una carpeta llamada css en public.
  5. Crearemos una carpeta llamada images en public, donde depositaremos el fondo de la columna derecha.
Contenido del fichero application/layouts/scripts/layout.phtml
<?php
echo $this->doctype ();
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<?php
echo $this->headTitle ();
echo $this->headScript ();
// add a link to the site style sheet
$this->headLink ()->appendStylesheet ( '/css/layout.css' );
echo $this->headLink ();
?>
</head>
<body>
 <div id="container">
  <div id="header">
   <h1>Zend Framework CMS</h1>
  </div>
  <div id="navigation">
  <?php echo $this->layout()->nav;?>
 </div>
  <div id="content-container">
   <div id="content">
   <?php echo $this->layout()->content?>
  </div>
   <div id="aside">
   <?php echo $this->layout()->subNav;?> 
  </div>
   <div id="footer">
    <em>Powered by the Zend Framework</em>
   </div>
  </div>
 </div>
</body>
</html>
Contenido del fichero public/css/layout.css:

@CHARSET "ISO-8859-1";

#container {
 margin: 0 auto;
 width: 100%;
 background: #fff;
}

#header {
 background: #ccc;
 padding: 20px;
}

#header h1 {
 margin: 0;
}

#navigation {
 float: left;
 width: 100%;
 background: #333;
}

#navigation ul {
 margin: 0;
 padding: 0;
}

#navigation ul li {
 list-style-type: none;
 display: inline;
}

#navigation li a {
 display: block;
 float: left;
 padding: 5px 10px;
 color: #fff;
 text-decoration: none;
 border-right: 1px solid #fff;
}

#navigation li a:hover {
 background: #383;
}

#content-container {
 float: left;
 width: 100%;
 background: #FFF url(/images/layout-two-liquid-background.gif) repeat-y 68% 0;
}

#content {
 clear: left;
 float: left;
 width: 60%;
 padding: 20px 0;
 margin: 0 0 0 4%;
 display: inline;
}

#content h2 {
 margin: 0;
}

#aside {
 float: right;
 width: 26%;
 padding: 20px 0;
 margin: 0 3% 0 0;
 display: inline;
}

#aside h3 {
 margin: 0;
}

#footer {
 clear: left;
 background: #ccc;
 text-align: right;
 padding: 20px;
 height: 1%;
}

Hemos de incluir el directorio de layouts creado en nuestro fichero de configuración para que la aplicación cargue sus contenidos. Para ello editamos application/configs/application.ini y añadimos en la sección production la entrada :

resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"

Para finalizar sustituiremos el contenido del portal por un texto más simple. Para ello editaremos el fichero application/views/scripts/index/index.phtml con el siguiente código:
<h2>Home</h2>
<p>Esta es la página Home por defecto...</p>

Podemos probar el resultado navegando en http://localhost:


Filosofía de ZendFramework

Zend Framework son un conjunto de librerías para el desarrollo de aplicaciones PHP creadas por al empresa Zend. Zend está detrás de Zend Framework pero son muchas más las empresas que han aportado para que este proyecto evolucione y tenga una continuidad en el tiempo.
Zend Framework se basa en una arquitectura Modelo-Vista-Controlador.



  • Modelo: Ofrece una capa de abstracción sobre los datos de nuestra aplicación, aporta las funcionalidades básicas de rutinas de acceso a los datos.
  • Vista: Es la encargada de la representación de los datos de la capa Modelo, es la encargada de aportar las funcionalidades básicas de interacción de los usuarios y nuestra aplicación.
  • Controlador: Es el encargado de gestionar las peticiones de interacción con nuestras vistas y el árbitro que gestiona el flujo de datos de nuestra aplicación.
A grandes rasgos podemos decir que cada modelo que define nuestra lógica de la aplicación tendrá un controlador asociado, el cual nos definirá las posibles acciones que sobre el modelo de datos se podrá interaccionar, así como las diferentes vistas en forma de HTML que tendrá como resultado la ejecución de las acciones del controlador.

La arquitectura de directorios básica de Zend Framework tiene como elementos principales:
  • application: es donde tendremos ubicados todos los elementos de la arquitectura Modelo-Vista-Controlador. Dentro encontraremos las carpetas models, viewscontrollers, correspondientes a la ubicación de los modelos, vistas y controladores. Además en application encontraremos la carpeta configs donde definiremos los parámetros de configuración de la aplicación.
  • docs: Destinado a la documentación de nuestra aplicación.
  • library: En esta carpeta irá el código de nuestras librerías, eso incluye si se desea Zend Framework, aunque es más flexible tener Zend Framework en una ubicación común a todas las aplicaciones y definir su ruta en el include_path del php.ini.
  • public: Carpeta donde irán ubicados todos los archivos requeridos por el servidor al servir las vistas, tales como ficheros css, imágenes, etc.
  • test: Directorio destinado a los scripts de prueba, pueden escribirse a mano, test PHPUnit, etc.
Cabe destacar dentro del directorio public el archivo index.php, es el encargado de iniciar toda la aplicación instanciando un objeto del tipo Zend_Application y lanzando el método run de la clase Bootstrap.
La clase Bootstrap está en la raíz del directorio application, en el fichero Bootstrap.php, su propósito es inicializar la aplicación, ajustar las preferencias del entorno (la zona horaria, el nivel del error_reporting, etc), además de otros ajustes específicos al procesamiento que hace la aplicación de las vistas como por ejemplo la codificación.



Integración con Zend Studio Client

Ahora que ya hemos creado nuestro proyecto vamos a integrarlo con nuestro entorno de desarrollo. Yo personalmente uso Zend Studio Client, y en esta entrada explicaré como integrarlo con nuestro proyecto ya creado.

En Zend Studio Client seleccionamos del menú File -> New -> PHP Project from Existing Directory.
Inmediatamente nos mostrará un cuadro de diálogo para especificar el nombre del proyecto, en nuestro caso CeDocCMS, que es el nombre de la carpeta creada anteriormente. Recordemos que el proyecto se creó en la carpeta C:\Zend\Apache2\htdocs



Al especificar el proyecto seleccionaremos "Detect Local" para que sea el mismo Studio Client quien interaccione con nuestro servidor local.

 Al detectar la instalación local de nuestro ZendServer nos solicitará contraseña de administrador.


Al finalizar la instalación podemos seleccionar los paquetes de librerías que añadiremos, este es un paso opcional que más adelante pueden ser añadidas.


Finalmente disponemos de nuestro proyecto para trabajar con él desde Zend Studio.


Zend Server - Creando el proyecto

La elección de la carpeta destino de nuestro proyecto depende de nuestros gustos, más adelante definiremos un host vitual en la configuración de Apache para acceder a nuestro portal, así que en principio no nos debe preocupar mucho. Si trabajamos con un IDE como Zend Studio Client al hacer una distribución del proyecto (Deploy) o una depuración veremos que Zend Server usará unas carpetas diferentes.
Así pues nuestros proyectos los prodemos ubicar en la carpeta C:\Zend\Apache\htdocs.
Nota: Podemos escoger nuestra carpeta de proyectos "workspace", yo es la que suelo utilizar, principalmente porque la carpeta htdocs ubicaré otros portales ajenos a Zend como por ejemplo phpMyAdmin, y así no mezclar nuestros proyectos con otros portales. Para mayor comodidad en las rutas del proyecto de aquí en adelante usaré htdocs.

Hay varias formas de crear un proyecto. Si hemos instalado ZendServer es tan sencillo como desde línea de comandos, estando en la carpeta de proyectos ejecutar la herramienta de Zend (Zend Tool Framework):
zf create project prueba

El desarrollo de aplicaciones en Zend se basa en el uso de las librerías de ZendFramework, en el caso de tener instalado ZendServer el sistema ya tiene una referencia a las carpetas de las librerías de ZendFramework, ubicadas en C:\Zend\ZendServer\share\ZendFramework, debemos tener configurada la la variable include_path con ruta de las librerías en nuestro php.ini
include_path=".;c:\Zend\ZendServer\bin\pear;C:\Zend\ZendServer\share\ZendFramework\library"
Otra opción es descargarse las librerías de Zend y copiarlas directamente en la carpeta library de nuestro proyecto.

Para más información consultar Create Your Project.

Para nuestro proyecto usaremos la herramienta antes mencionada zf.bat de ZendServer, que nos creará automáticamente la estructura de directorios para nuestro proyecto CeDocCMS:

C:\Zend\Apache\htdocs>zf create project CeDocCMS

Vemos que al ejecutar el comando se ha creado la siguiente estructura de directorios:

CeDocCMS
|-- application 
|   |-- Bootstrap.php
|   |-- configs
|   |   `-- application.ini
|   |-- controllers
|   |   |-- ErrorController.php
|   |   `-- IndexController.php
|   |-- models
|   `-- views
|       |-- helpers
|       `-- scripts
|           |-- error
|           |   `-- error.phtml
|           `-- index
|               `-- index.phtml
|-- library
|-- public
|   |-- .htaccess
|   `-- index.php
`-- tests
    |-- application
    |   `-- bootstrap.php
    |-- library
    |   `-- bootstrap.php
    `-- phpunit.xml

Ahora crearemos un host virtual en Apache que apunte a nuestro proyecto. El fichero donde definiremos nuestros hosts virtuales será conf/extra/httpd-vhosts.conf, pero antes será necesario incluir dicho fichero en la configuración de Apache para que lo tenga en cuenta.
Editaremos C:\Zend\Apache2\conf\httpd.conf y quitaremos los comentarios a la línea donde está definido httpd-vhosts.conf.
# Virtual hosts
Include conf/extra/httpd-vhosts.conf
En el fichero de hosts virtuales añadiremos la entrada de nuestro hosts.
Nota: Hemos de editar el fichero httpd-vhosts.conf puesto que hay hosts virtuales de ejemplo que hemos de eliminar.
Nota: Al crear nuestro proyecto con la Zend Tool Framework en el directorio C:\Zend\Apache2\htdocs\CeDocCMS\docs tenemos a nuestra disposición el fichero README.txt con la definición de ejemplo de nuestro hosts virtual.

<VirtualHost *:80>
   DocumentRoot "C:/Zend/Apache2/htdocs/CeDocCMS/public"
   ServerName .local

   # This should be omitted in the production environment
   SetEnv APPLICATION_ENV development   ErrorLog "logs/CeDodCMS.example.com-error.log"
   CustomLog "logs/CeDodCMS.example.com-access.log" common

   <Directory "C:/Zend/Apache2/htdocs/CeDocCMS/public">
       Options Indexes MultiViews FollowSymLinks
       AllowOverride All
       Order allow,deny
       Allow from all
   </Directory>

</VirtualHost>
Nota: Añadiremos al ejemplo del README.txt la definición personalizada de la generación de logs.

Reiniciaremos el servidor para aplicar los cambios realizados. Si ahora consultamos nuestro localhost veremos el proyecto en funcionamiento:



lunes, 10 de febrero de 2014

Zend - Ultimando la instalación de Zend Server

Para finalizar la instalación del servidor es conveniente instalar PEAR. Para ello desde la línea de comandos podemos ejecutar:

c:\>cd c:\Zend\ZendServer\bin
c:\Zend\ZendServer\bin>go-pear.bat


Pulsaremos Enter y seleccionaremos todos los directorios por defecto.
Nota: Nos añadirá una entrada en nuestro archivo php.ini con el directorio del PEAR.

;***** Added by go-pear

include_path=".;c:\Zend\ZendServer\bin\pear;C:\Zend\ZendServer\share\ZendFramework\library"

;*****
Ahora podemos instalar PHPUnit
c:\Zend\ZendServer\bin>cd pear
C:\Zend\ZendServer\bin\PEAR>pear config-set auto_discover 1
Mostrará un mensaje del estilo "config-set succeeded". Seguidamente ejecutamos la instalación de PHPUnit:
C:\Zend\ZendServer\bin\PEAR>pear install pear.phpunit.de/PHPUnit

Nota: En algunas circunstancias valora la posibilidad de reinicar el equipo para que los cambios surgan efecto. En el caso de Zend Server es posible que muestro un error de configuración en la variable include_path, dado que reconoce que su valor difiere del que tiene almacenado. El mensaje podría tener la siguiente forma:
The directive 'include_path' is mismatched: expected '".;C:\Zend\ZendServer\share\ZendFramework\library"', actual '".;c:\Zend\ZendServer\bin\pear;C:\Zend\ZendServer\share\ZendFramework\library"'

Aplicaríamos cambios y reiniciaríamos el servidor Zend.

Zend - Primeros pasos

Todo proyecto informático nace de una necesidad, en concreto la mía es hacer una pequeña aplicación en PHP para la creación de un inventario para una biblioteca, y para ello me serviré de ZendFrameWork.

Consideraciones previas

En estos ejemplos usaré una instalación fresca de ZendServer y como IDE de desarrollo ZendStudio 10.6. Todos los ejemplos están hechos en una máquina Windows, más adelante abordaré la carga del código en una máquina de producción Linux.
En el primer caso no es necesario que exista pues con el esqueleto de Zend FrameWork sería suficiente y en el caso del IDE es a gusto del consumidor.
ZendServer se ha instalado en la raíz del sistema, así que su ruta de acceso es "C:\Zend", así pues todos los proyectos estarán ubicados en "c:\Zend\Apache2\htdocs".

Empezando

Instalación de ZendServer. Para descargarlo es necesario tener un usuario registrado en http://www.zend.com/en/downloads/, allí seleccionaremos Zend Server. En el momento de escribir esta entrada la versión de Zend Server era 6.2.0. La versión de PHP es a gusto del usuario, yo instalé la 5.4
Nota: Sería recomendable instalar también MySQL

La primera pantalla es la de bienvenida:

La segunda hace referencia a la licencia, aceptamos si estamos de acuerdo y proseguimos.
 En la tercera pantalla elegiremos la opción "custom":

En la siguiente pantalla buscaremos la opción de instalación de MySQL Server y lo seleccionaremos:

Nota: podría ser interesante añadir más productos como por ejemplo IBM DB2 RTCL para acceder a sistemas iSeries.
En la siguiente pantalla seleccionaremos el path de instalación, para hacerlo más cómo ubicaremos a Zend Server en la raíz.

La siguiente pantalla nos pide los puertos de escucha para el servicio de páginas web y la administración del servidor. Atención si en nuestra máquina ya existen servidores web que usen esos puertos, quizás el puerto 80 debamos cambiarlo por 10080.

Instalación final pulsamos "Install":

Al finalizar la instalación nos permitirá ejecutar el servidor instalado, a lo cual respondemos que sí seleccionando la opción, inmediatamente nos abrirá un navegador con la url del servidor. Aceptaremos el contrato de licencia si estamos de acuerdo.
En la siguiente pantalla decidiremos si nuestro servidor será de desarrollo o producción, en mi caso fundamentalmente será desarrollo.
En la siguiente pantalla se nos solicita las contraseñas.

Finalmente si la instalación ha ido correctamente podremos ver el resultado:
Si consultamos el localhost ahora aparecerá la página de inicio de ZendServer: