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)