Libertonia
Portada · Todo · Software Libre · Desarrolladores · Comunidad · Internet · Tecnología · Meta · Diarios
CRUD con Catalyst

Programación
Por jamarier
departamento Frameworks web y Perl. argggg!!!!!! , Sección Internet
Puesto a las Fri Dec 9th, 2005 at 06:15:57 PM CET

Continuación de la Mini-intro-Tutorial de Catalyst.

Hoy vamos a efectuar un ejemplo más completo. Para ello vamos a basarnos en en un tutorial de Ruby on Rails y en un screencast de Catalyst (scaffolding).

 


La instalación

Catalyst evoluciona muy rápidamente y los paquetes que ofrece Debian no están todo lo actualizado que deberían, así que hacemos una instalación manual en el /usr/local/ desde el CPAN.

cpan -i Bundle::Catalyst

La instalación desde CPAN es un poco larga y pesada y en alguna ocasión, se ha detenido por referencias incumplidas. En cuyo caso, se vuelve a ejecutar el comando hasta que no dé error. De todas formas, al parecer esto no incluye todos los paquetes necesarios (y dependerá de como tengamos la instalación de Perl en nuestra máquina). Así que cada vez que intento ejecutar alguno de los scripts que menciono si me da error diciendo que no encuentra un paquete lo instalo

cpan -i [nombre::del::paquete::que::falta]

También vamos a necesitar una base de datos disponible. Para simplificar la tarea usaremos sqlite versión 3

apt-get install sqlite3

El proyecto

El proyecto será la creación de un sitio web online de recetas de cocina comunitario. Queremos que nuestro libro de recetas:

  • Muestre una lista de todas las recetas
  • Crear nuevas recetas o modificar las anteriores
  • Poder asignar a cada receta una categoría (como «postre» o «sopa»)

Añadido respecto al tutorial de RoR, esta es una típica aplicación que se conoce como CRUD (Create, Read, Update, Delete) se mencionó en un comentario de la otra entrada que Maypole (otro framework para Perl) estaba diseñada especialmente para este tipo de tareas. Aun así, vamos a demostrar en este texto que Catalyst no se queda atrás.

Creación del esqueleto base y prueba inicial

Vamos al directorio de nuestra elección y ejecutamos el script inicial

catalyst.pl -short Cookbook

Nos genera un directorio llamado Cookbook con una serie de subdirectorios que son:

lib
Donde se encuentra el código de nuestra aplicación web.
root
Es el directorio donde poner los recursos estáticos de nuestra web. Tales como iconos u hojas de estilos.
scripts
Utilidades que nos facilita la labor de diseñar la aplicación. Tales como un servidor web para probar la aplicación o utilidades para hacer funcionar la web como fastcgi. Han cambiado la nomenclatura respecto al otro tutorial, ahora los scripts se llaman [nombre del proyecto]_loquesea.pl.
t
Catalyst está diseñado usando test unitarios. Los ficheros que va generando a nuestra petición incluyen los test correspondientes. En este directorio están disponibles los test a efectuar sobre nuestra aplicación. Obviamente se pueden añadir los nuestros propios cuando queramos.

Catalyst tiene dos sistemas de nombrar sus directorios, el largo y el corto. Al parecer, el asistente que usaremos (Scanffold) genera sus archivos usando la nomenclatura corta, así que para mantener homogeneidad, emplearemos la nomenclatura corta en todos nuestros scripts.

La prueba inicial de que todo funciona es ejecutar el miniservidor:

script/cookbook_server.pl

Nos indica que podemos acceder a nuestra página en el puerto 3000 de nuestra máquina. En mi caso: http://domagxo:3000 (también vale http://localhost:3000). La web que sale es bonita pero aún no se parece mucho a un libro de cocina. ;-)

Creación del control de la aplicación

Los controladores los podemos considerar como los programas (pueden existir más de uno), que leen la url de la página y determinan que se hace con ella. Por ejemplo, en el caso de libertonia, podríamos hablar de un controlador «user» que toma los siguientes parámetros de la url para mostrar los datos de un usuario registrado, o el controlador «story» cuyos siguientes datos son fechas y otras cosas.

Vamos a crear un controlador llamado Cookbook. Después si queremos podemos redireccionar para que siempre se utilice este controlador y nos ahorramos el tener que escribir «cookbook» en todas las urls. Fijaos que no hay inconveniente en que el controlador se llame igual que el proyecto. El fichero principal del proyecto es /lib/Cookbook.pm y los controladores se instalan en /lib/Cookbook/C/. La 'C' es de Controller, esto es así por usar la nomenclatura corta.

script/cookbook_create.pl -short controller Cookbook Scaffold CDBI::Recipes

Analicemos el comando: Le estamos diciendo que nos cree un controlador (con los ficheros necesarios) llamado Cookbook, usando un asistente llamado Scaffold y que el Modelo (donde se almacena la información, la tabla de nuestra base de datos) será CDBI::Recipes.

Entre otras cosas genera: un fichero de test (t/controller_Cookbook.t) y plantillas de ficheros html para añadir, editar, listar y mostrar recetas. (todos terminan en .tt porque scaffold usa el sistema de plantillas Template Toolkit).

Creando la base de datos y su correspondiente modelo

Hemos hablado del nombre del modelo que usaremos «CDBI::Recipes», pero aún no lo hemos creado ni tampoco hemos creado la base de datos relacionada. Como comenté al principio, trabajaremos con la base de datos sqlite3. Partimos de la descripción de la base de datos en sql. Creamos un fichero llamado cookbook.sql con el siguiente contenido:

CREATE TABLE recipes (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  title VARCHAR(255),
  description VARCHAR(255),
  date DATE,
  instructions TEXT
);

Y ahora creamos la base de datos:

sqlite3 cookbook.db < cookbook.sql

Nuestra siguiente misión es la de crear el modelo o lo que es lo mismo, como nuestro sistema va a interaccionar con la base de datos. Para ello usamos otra vez un asistente.

script/cookbook_create.pl -short model CDBI CDBI dbi:SQLite:/home/javi/propios/programacion/perl/Catalyst/Cookbook/cookbook.db

(ojo, todo es una sola línea)

Por cada tabla definida en la base de datos, tendremos un «submodelo». Así que nuestra tabla Recipes se convierte en CDBI::Recipes y queda cerrado el cabo que teníamos abierto en la definición del controlador.

Otra vez analizamos la línea: creamos un modelo llamado CDBI usando un asistente llamado CDBI (esta repetición de nombres parece un convenio), y por último el identificador de la base de datos. Aunque esto sería como para otro artículo completo, mencionaré que el interfaz de bases de datos dbi tiene más de cien bases de datos adaptadas. Así que cambiando ese descriptor podemos usar mysql, postgresql, ficheros cvs, oracle... ver este listado de cpan si hay curiosidad de las bases de datos disponibles.

Creación de la Vista

Nuestro asistente scaffold nos ha creado plantillas para la vista. Aunque no hemos creado aun la vista. (la clase que se encarga de tomar los datos y las plantillas para obtener el html final).

script/cookbook_create.pl -short view TT TT

Y ahora las manos en la masa

Primero es conectar al controlador general lib/Cookbook.pm la vista por defecto: Cookbook::View::TT.

Editamos lib/Cookbook.pm y hacemos dos modificaciones:

  • Añadimos el plugin FormValidator, para que valide automáticamente los campos de la base de datos de los formularios

    Sustituimos:

    use Catalyst qw/-Debug Static::Simple/;

    por

    use Catalyst qw/-Debug Static::Simple FormValidator/;
  • En medio del texto hay comentado una subrutina (end) la descomentamos indicando nuestra clase View:
    =item end
    
    =cut
    
    sub end : Private {
    	my ( $self, $c ) = @_;
    	
    	# Forward to View unless response body is already defined
    	$c->forward('V::TT') unless $c->res->output;
    
    }
    

La subrutina «end» se ejecuta por defecto en todos las peticiones. La página que se envía al navegador es $c->res->output. Así que si esta no está definida ya (porque haya habido algún error y sea un informe de error o porque se haya usado una Vista alternativa, por ejemplo), transferimos la ejecución a nuestro objeto Vista por defecto.

La segunda modificación que necesitamos es darle a las clases Modelo, la capacidad de convertirse de y a html. La clase que generamos CDBI es clase base de cada tabla, las modificaciones efectuadas ahí, tienen efecto en todas sus clases hijas.

Solo hay que añadir la línea que pone «additional_base_classes»

__PACKAGE__->config(
	dsn           => 'dbi:SQLite:/home/javi/propios/programacion/perl/Catalyst/Cookbook/cookbook.db',
	user          => '',
	password      => '',
	options       => {},
	additional_base_classes => [qw/Class::DBI::FromForm Class::DBI::AsForm/]
	relationships => 1
);

Para cambiar la base de datos, solo es necesaria cambiar la línea del identificador «dsn» y si fuera necesario indicar usuario y contraseña.

Primera prueba

Ya podemos ejecutar nuestra primera versión del invento. Ya sabéis:

script/cookbook_server.pl

Y tenemos que ir a http://localhost:3000/cookbook/ para que el controlador que hemos creado actúe. Bastante feo, pero funciona. Si lo comparamos con las capturas del tutorial de RoR, veremos dos diferencias fundamentales:

La primera es que en RoR, la fecha se introduce usando combobox, y con Catalyst es una entrada de texto. Este problema no es de Catalyst, es de sqlite que las fechas las considera como cadenas de texto. Así que al elaborar el formulario, pide una cadena de texto. Tiene solución, aunque no automática. Para solucionarlo tendríamos que tocar la plantilla de añadir/editar fichas y sustituir esa entrada de texto por los componentes adecuados y luego hacer una conversión de dicho formulario a una cadena para poder introducirla en la base de datos. Supongo que usando otras bases de datos este problema no se daría (si alguien lo prueba, que comente sus experiencias).

La segunda diferencia es el orden en el que se presentan los diversos campos. Están por orden alfabético en vez de por orden de definición. esto está ocasionado por el modelo empleado CDBI. Este considera que cada línea de la base de datos es un hash de Perl (una agrupación tipo diccionario, tu preguntas por el campo y te devuelve su contenido) y los hash no son ordenados. Así que, lo único que se puede hacer aquí es tocar las plantillas de visualización (los ficheros .tt) para que muestren el orden de la forma deseada. De hecho, en el tutorial de RoR se hace así, es decir se crea una plantilla para que los datos salgan en el orden que les interesa. Aquí lo dejaremos como ejercicio. ;-)

Añadiendo las categorías a las recetas

Primero tenemos que crear, la tabla en nuestra base de datos. Por simplificar el proceso, vamos a recrear la base de datos completa. Modificamos cookbook.sql para que quede así:

CREATE TABLE recipes (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  title VARCHAR(255),
  description VARCHAR(255),
  date DATE,
  instructions TEXT,
  categories_id INTEGER,
  FOREIGN KEY (categories_id) REFERENCES categories(id)
);

CREATE TABLE categories (
	id INTEGER PRIMARY KEY AUTOINCREMENT,
	name VARCHAR(255)
);

La tabla «recipes» tiene un campo nuevo: categoria_id que apunta a una entrada en la tabla «categories».

Recreamos la estructura de la base de datos:

script/cookbook_create.pl -short model CDBI CDBI dbi:SQLite:/home/javi/propios/programacion/perl/Catalyst/Cookbook/cookbook.db
.

(de nuevo, esta es tambien solo una línea)

Si Catalyst pretende modificar un fichero que ya ha sido modificado por nosotros, lo que hace es crear un fichero con el mismo nombre pero añadiendo .new al final del mismo. Así podemos comparar el nuevo fichero con lo que teníamos y resolver qué escogemos de cada cosa. En este caso, aunque hayamos modificado la estructura de la tabla «recipes», la clase que la controla no ha sido modificada, en cambio, si que hemos creado una nueva clase: CDBI::Categories para nuestra nueva tabla.

El segundo paso es crear el controlador para poder añadir/editar/modificar categorías:

script/cookbook_create.pl -short controller Categories Scaffold CDBI::Categories

Al cargarse la base de datos, identifica la relación entre las dos tablas y se encarga de visualizar el enlace a la otra tabla(*). Aunque en principio usa la clave principal (un número en nuestro caso) como identificador en la columna. Así que vamos a indicarle que queremos que use como identificador la columna «name». Para eso, en el fichero lib/Cookbook/M/CDBI/Categories.pm incluimos tras «use strict» la siguiente línea:

__PACKAGE__->columns(Stringify => qw/name/);

Y con esto hemos llegado al final del tutorial de RoR y de nuestro tutorial. Dicho artículo tiene una segunda parte en el que se habla de registro y sesiones. Eso quedará para otra entrada.

[*] Montando el artículo he descubierto una errata en la versión 0.22 de la clase Class::DBI::Loader::SQLite (sobra un ^ en el if final de la función _relationship). Ya se lo he comunicado al autor y supongo que en breve se publicará una nueva versión del fichero con ese error subsanado. Así que si no tenéis mucha gana de pelearos usad otra base de datos o esperad a que se publique la versión corregida. (Sin corregir, las tablas no se relacionarán).

< Una de estándares abiertos (9 comments) | Gentoo al desnudo (13 comments) >
Enlaces Relacionados
· escomposlinux.org
· Mini-intro-Tutorial de Catalyst
· un tutorial de Ruby on Rails
· un screencast de Catalyst
· listado de cpan
· More on Programación
· Also by jamarier

Encuesta
Siguiendo con Catalyst
· Casi mejor que no sigas, esto no interesa 0%
· Sigue por la segunda Parte del Tutorial de RoR (mejoras de usabilidad) 50%
· Sigue por un «CataWiki» 25%
· Mejor un blog «Catablog» 0%
· Mejor aun: un blog comunitario, el «Catatonia» 12%
· Cosas específicas como cookies o autenticación. 12%
· Otros (a indicar) 0%

Votos: 8
Resultados | Otras Encuestas

Menu
· crear cuenta
· FAQ
· búsqueda
· Fuentes de Noticias

Login
Nueva cuenta
Usuario:
Contraseña:

Ver: Modo: Orden:
CRUD con Catalyst | 3 comentarios ( temáticos, 3 editoriales, 0 ocultos)
Ver: Modo: Orden:

ecol Logo Powered by Scoop
Todas las Marcas Registradas y copyrights de esta página son propiedad de sus respectivos dueños.
Los comentarios son propiedad del que los escribe.
Los iconos de las noticias y el logotipo son propiedad de Javier Malonda.
El Resto © 2002 Escomposlinux.org y aledaños.

Puedes sindicar los contenidos de libertonia en formato RSS 1.0 y RDF 0.9. También se puede sindicar la cola de envíos pendientes de moderación.

El proyecto escomposlinux.org está dedicado a la memoria de tas

crear cuenta | faq | búsqueda