Mostrando entradas con la etiqueta ArgoUml. Mostrar todas las entradas
Mostrando entradas con la etiqueta ArgoUml. Mostrar todas las entradas

martes, 9 de septiembre de 2008

Experimentado con ArgoUML y CodeIgniter

Llevaba bastante tiempo con ganas de probar Codeigniter. Después de comparar Symfony y Zend Framework hace unos cuantos meses, alguien me sugirió hacerlo. Por cierto con los avances que han tenido cada uno de estos proyectos dicha comparativa está prácticamente obsoleta.

La semana pasada empecé a trastear con CodeIgniter y volví a darle vueltas a la cuestión de que no tuviera una serie de comandos para ayudar con la generación de controladores, modelos, etc. Así que se me ocurrió utilizar mi querido ArgoUml para "pintar" las clases y después generarlas en los directorios del proyecto.

El genearador de código PHP

Entonces me di de bruces con lo que para mí es un viejo problema en la generación de clases de ArgoUML: añade el prefijo "class." al nombre de tu clase como nombre de fichero. Es decir, si tu clase se llama Clientes obtendrás un fichero de nombre class.Clientes.php. Me topé por primera vez con esto en un proyecto llevado a cabo en mi trabajo en el que la capa de presentación está hecha en Flex y el resto en PHP. Nos encontramos con la restricción, por parte de AmfPHP, de que el nombre de las clases y los ficheros que la contienen debe ser el mismo. Esta misma obligación nos la encontramos en CodeIgniter, o sea, nuestra clase Clientes deberá encontrarse en el fichero clientes.php.

Otro convenio utlizado por ArgoUML me terminaría afectado: el nombre de las clases generadas tiene antepuesto toda la cadena de paquetes de la que depende. Me explico: si nuestra clase Clientes pertenece al paquete modelo, tomará como nombre modelo_Clientes.

Estuve pensando como salvar esta dificultades pero las cosas que se me ocurrían no eran muy limpias. Finalmente opté por una solución que tampoco es como para estar orgulloso pero me pareció con bastante diferencia la mejor: recompilar el módulo generador de código PHP de ArgoUML a mi gusto.

¡Viva el código libre! Un par de cambios y a volar

Pues nada a navegar por la página de Argo y buscar el código fuente del subproyecto ArgoUML-PHP. No cuesta mucho dar con el repositorio SVN así que un checkout y ya tenía el código en mi PC.

Después de esto tengo que reconocer que la cosa fue bastante fácil, si no, os aseguro que la pereza hubiese podido conmigo. El código descargado viene con el archivo de proyecto para abrirlo en Eclipse. Nos encotraremos algún problema de dependencias con archivos .jar que podremos obtener de la propia instalación de Argo. Una vez resueltas sólo hay que abrir el fichero NameGenerator.java y localizar dos porciones de código.

La primera corresponde a la nomenclatura de las clases con el prefijo de paquetes. Hay que comentar el código tal como veis aquí:


public static final String generateClassifierName(Object modelElement) {
if (!Model.getFacade().isAClassifier(modelElement)) {
throw new ClassCastException(modelElement.getClass()
+ " has wrong object type, Classifier required");
}

String sName = Model.getFacade().getName(modelElement);

/*String sPackageName = generatePackageName(modelElement);
if (sName != null && sPackageName != null
&& sPackageName.length() > 0) {
sName = sPackageName + "_" + sName;
}*/

return sName;
}


El segundo cambio es el del nombre del fichero:


if (iMajorVersion > 4) {
if (Model.getFacade().isAInterface(modelElement)) {
sFilename += "interface.";
} else if (Model.getFacade().isAClass(modelElement)) {
sFilename += "class.";
} else {
sFilename += "unknown.";
}
}


se cambia la cadena "class." por la vacía y resuelto.

Después de hacer esto creamos nuestro .jar y sustituimos el existente en el directorio /ext de la intalación de ArgoUML. Al principio el programa no me lo cogía, al generar código no me aparecían las opciones PHP4 ni PHP5, finalmente lo resolví eliminado el archivo manifest del .jar.



Modelando

Lo primero que tendremos que hacer es imitar la parte de la estructura de CodeIgniter que nos interesa. Para ello crearemos un proyecto nuevo en Argo y después un paquete llamado models y otro llamado cotrollers. Hacemos esto para que llegados al momento de generar código asignemos como ruta nuestro path a Codeigniter/system/application y cada una de las clases vayan a su directorio correspondiente.



Aviso que necesitaremos añadir al path de PHP la ruta hasta CodeIgniter/system/application por la forma en la que Argo nos escribirá los requires entre clases.

Ya solo nos queda un quebradero de cabeza. Todas nuestras clases de controlador deberían heredar de la clase Controller de CodeIgniter pero si representamos la misma en nuestro modelo se nos creará un require de una clase que no debería existir (ya está definida en el framework). La solución que se me ocurrió para esto fue añadir una clase adaptador MiController que hereda de Controller de Codeigniter. Esta clase la generaremos sólo una vez ya que después le añadiremos en el editor "extends Controller" y si volvemos a generarla machacaremos el cambio y tendremos que volver a escribirlo. Después todas las clases controlador que creemos heredarán de MiController.


class MiController extends Controller
{
// --- ASSOCIATIONS ---


// --- ATTRIBUTES ---

// --- OPERATIONS ---

/**
* Short description of method __construct
*
* @access public
* @return mixed
*/
public function __construct()
{
// section -87--2--75--55--89caeb7:11c46a97fcc:-8000:00000000000008BA begin
parent::__construct();
// section -87--2--75--55--89caeb7:11c46a97fcc:-8000:00000000000008BA end
}

}


Lo mismo nos ocurrirá con las clases modelo pero la solución es exáctamente la misma.


class MiModelo extends model
{
// --- ASSOCIATIONS ---


// --- ATTRIBUTES ---

// --- OPERATIONS ---

/**
* Short description of method __construct
*
* @access public
* @author Depto. Web/WAP de Alvento Soluciones, <guillermo@alvento.com>
* @return mixed
*/
public function __construct()
{
// section -87--2--75--55-438df237:11c46b7f1db:-8000:0000000000000878 begin
parent::Model();
// section -87--2--75--55-438df237:11c46b7f1db:-8000:0000000000000878 end
}

} /* end of class MiModelo */


Una vez hecho esto podremos modelar tranquilamente creando nuestras clases, modificándolas en Argo y volviendo a generar el código sin perder lo que hayamos escrito en el IDE (como ya expliqué en su día)




domingo, 23 de marzo de 2008

Modelando con ArgoUML aplicaciones en PHP

Sobre ArgoUML

ArgoUML (Argo para abreviar) es una de esas aplicaciones que dan la impresión de no ser utilizadas por mucha gente pero que, sin embargo, continúan desarrollandose con un ritmo incansable. Para los que no lo sepan se trata de una herramienta CASE para modelar software en UML.

En mi caso elegí Argo porque quería modelar con una herramienta libre que me generase código en PHP. Además debería correr tanto en Windows como en Linux.

Pero antes de eso y después de probar unas cuantas herramientas veía difícil encontrar una aplicación que cumpliera estos tres requisitos: podía producir código PHP con Umbrello pero no corría en Windows, Visual Paradigm era hasta bonito pero no libre, etc. Finalmente llegué hasta Argo y aunque en una primer vistazo puede parecer una herramienta tosca en comparación con otras, cuando te acostumbras te das cuenta de que es bastante rápido trabajar con ella.


Para los fanáticos de Eclipse existe un proyecto paralelo llamado argoeclipse que nos permite tenerlo integrado en dicho IDE. Sin embargo este proyecto siempre va un paso por detrás de su hermano mayor y creo que cuando lo probé no generaba código PHP.


Modelando

Tenemos a nuestra disposición los diagramas de casos de uso, clases, secuencia, colaboración, estado y despliegue.


Particularmente suelo utilizar el de casos de uso para definir historias o partes del entorno de usuario, el de clases para el análisis, desarrollo y documentación.








Ocasionalmente uso el de actividades para definir algún proceso que me interesa plasmar por su complejidad y el de despliegue como apoyo de algún documento.


Dada su flexibilidad, no importa que tipo de modelado queramos hacer. Por ejemplo, para un diagrama de clases, si modelamos desde el punto de vista del diseño de aplicación podemos ocultar atributos y funciones:

Por el contrario podemos profundizar un poco más en el análisis y definir atributos y funciones de las clases:

Por último si modelamos orientado a la implementación conviene que veamos la privacidad y los parámetros que utilizamos:


También nos es muy útil para documentar independientemente del nivel al que modelemos, ya que podemos insertar documentación sobre las clases, atributos, funciones, etc. Cuando generémos el código se nos insertarán los comentarios de forma que más tarde podremos procesarlo mediante PHPDocumentor y obtener un pdf o páginas html de documentación.

En la práctica

Volviendo a los diagramas que se pueden ver más arriba imaginemos que después de definir los casos de uso y de hacer un modelado de las clases a nivel de diseño, vamos profundizando hasta el punto de vista de implementación. Llegados a este punto es el momento de generar código. Para ello nos vamos hasta nuestro diagrama de clases y elegimos en el menú Generar la opción Generar todas las clases... y elegimos las clases que queramos generar y la ruta donde se crearán los archivos.



Después de esto obtendremos un fichero por cada una de las clases, por ejemplo para la clase artículo tendremos:


if (0 > version_compare(PHP_VERSION, '5')) {
die('This file was generated for PHP 5');
}

/**
* include Comentario
*
* @author firstname and lastname of author, author@example.org
*/
require_once('class.Comentario.php');

/* user defined includes */
// section -84-16-6-101-32d97df8:117d1aeef8e:-8000:0000000000000846-includes begin
// section -84-16-6-101-32d97df8:117d1aeef8e:-8000:0000000000000846-includes end

/* user defined constants */
// section -84-16-6-101-32d97df8:117d1aeef8e:-8000:0000000000000846-constants begin
// section -84-16-6-101-32d97df8:117d1aeef8e:-8000:0000000000000846-constants end

/**
* Esta clase representa los artículos que se escriben para el blog.
*
* @access public
* @author firstname and lastname of author, author@example.org
*/
class Articulo
{
// --- ATTRIBUTES ---

/**
* Identificador único
*
* @access private
* @var Integer
*/
private $idarticulo = null;

/**
* Título del artículo
*
* @access private
* @var String
*/
private $titulo = null;

/**
* Texto del artículo
*
* @access private
* @var String
*/
private $cuerpo = null;

/**
* Fecha de creación
*
* @access private
* @var Integer
*/
private $fecha_creacion = null;

// --- OPERATIONS ---

/**
* En realidad esta función debería insertar un nuevo
* artículo en la BD pero de momento sólo tiene código de prueba
*
* @access public
* @author firstname and lastname of author, author@example.org
* @param String titulo
* @param String cuerpo
* @return Boolean
*/
public function nuevoArticulo( String $titulo, String $cuerpo)
{
$returnValue = null;

// section -84-16-6-100--4073085f:118d2dc4603:-8000:000000000000086C begin
// section -84-16-6-100--4073085f:118d2dc4603:-8000:000000000000086C end

return $returnValue;
}

} /* end of class Articulo */



Como se puede observar hay comentarios introducidos por nosotros y unas extrañas marcas que nos permitirán volver a generar código sin perder lo que hayamos escrito entre ellas. Por ejemplo añadimos la instrucción:


$returnValue=true;


o sea:


public function nuevoArticulo( String $titulo, String $cuerpo)
{
$returnValue = null;

// section -84-16-6-100--4073085f:118d2dc4603:-8000:000000000000086C begin
$returnValue=true;
// section -84-16-6-100--4073085f:118d2dc4603:-8000:000000000000086C end

return $returnValue;
}


Ahora volvemos a Argo, añadimos otra función y volvemos a generar código:



*/

if (0 > version_compare(PHP_VERSION, '5')) {
die('This file was generated for PHP 5');
}

/**
* include Comentario
*
* @author firstname and lastname of author, author@example.org
*/
require_once('class.Comentario.php');

/* user defined includes */
// section -84-16-6-101-32d97df8:117d1aeef8e:-8000:0000000000000846-includes begin
// section -84-16-6-101-32d97df8:117d1aeef8e:-8000:0000000000000846-includes end

/* user defined constants */
// section -84-16-6-101-32d97df8:117d1aeef8e:-8000:0000000000000846-constants begin
// section -84-16-6-101-32d97df8:117d1aeef8e:-8000:0000000000000846-constants end

/**
* Esta clase representa los artículos que se escriben para el blog.
*
* @access public
* @author firstname and lastname of author, author@example.org
*/
class Articulo
{
// --- ATTRIBUTES ---

/**
* Identificador único
*
* @access private
* @var Integer
*/
private $idarticulo = null;

/**
* Título del artículo
*
* @access private
* @var String
*/
private $titulo = null;

/**
* Texto del artículo
*
* @access private
* @var String
*/
private $cuerpo = null;

/**
* Fecha de creación
*
* @access private
* @var Integer
*/
private $fecha_creacion = null;

// --- OPERATIONS ---

/**
* En realidad esta función debería insertar un nuevo
* artículo en la BD pero de momento sólo tiene código de prueba
*
* @access public
* @author firstname and lastname of author, author@example.org
* @param String titulo
* @param String cuerpo
* @return Boolean
*/
public function nuevoArticulo( String $titulo, String $cuerpo)
{
$returnValue = null;

// section -84-16-6-100--4073085f:118d2dc4603:-8000:000000000000086C begin
$returnValue=true;
// section -84-16-6-100--4073085f:118d2dc4603:-8000:000000000000086C end

return $returnValue;
}

/**
* Esta función debería borrar el artículo identificado mediante id.
*
* @access public
* @author firstname and lastname of author, author@example.org
* @param Integer id
* @return mixed
*/
public function borraArticulo( Integer $id)
{
// section -84-16-6-100--4073085f:118d2dc4603:-8000:000000000000088C begin
// section -84-16-6-100--4073085f:118d2dc4603:-8000:000000000000088C end
}

} /* end of class Articulo */

?>


¡Nuestro código sigue ahí!

Por último pasamos el proyecto por PHPDocumentor y obtenemos la documentación correspondiente.



Y eso es básicamente todo, si trabajáis en Web con PHP, os gusta modelar y tenéis tiempo para ello, ArgoUML es una gran elección.