Desarrollo de aplicaciones web usando Catalyst y jQuery

download Desarrollo de aplicaciones web usando Catalyst y jQuery

If you can't read please download the document

Transcript of Desarrollo de aplicaciones web usando Catalyst y jQuery

Javier E. Prez P.Noviembre 2007

Desarrollo de aplicaciones web usandoCatalyst y jQuery

Puntos a tratar

Qu es Catalyst?

Ventajas de su uso.

Requisitos de instalacin.

Creando un proyecto.

Estructura de proyecto.

Creacin de: Controlador, Modelo, Vista.

Agregando mdulos.

Conexin a base de datos (DBIC).

Trabajando con plantillas (TT, TTSite)

Trabajando con formularios (FormBuilder).

Uso de sessiones.

Autorizacin, autenticacin.

Depuracin.

Consejos.

Proyectos nacionales desarrollados usando catalyst.

Qu es Catalyst?

Framework Web escrito usando perl.

MVC.

Unicode.

Servidor de pruebas integrado.

Metodologa MVC

Modelo

De donde se almacenan los datos.

Generalmente base de datos.

Vista

La presentacin de los datos.

HTML, JSON, RSS, XML, etc.

Controlador

Quin maneja las transacciones entre la solicitud del usuario, el proceso y salida de informacin.

Catalyst itself

Ventajas de su uso

Ventajas de su uso

Despacho del URL, se trabaja por segmentos en vez de querystring's

Instalacin sencilla.

Estructura establecida de los directorios manteniendo un orden.

Est respaldado por la gran cantidad de mdulos que hospeda cpan.

Formularios

ORM's

Reportes

i18n

autenticatin, autorizacin.

etc.

Ventajas de su uso

Despacho del URL, se trabaja basado en segmentos en vez de querystring's.

http://www.google.com/search?hl=es&client=iceweasel-a&q=catalyst&btnG=Buscar

http://www.administracion.com/usuario?id=11222333&accion=eliminar

QueryString

http://www.google.com/search/lenguale/es/cliente/iceweasel-a/q/catalyst/Buscar

http://www.administracion.com/usuario/11222333/eliminar

Basado en segmentos (segment based)

use PDF::CreateSimple;

sub pdf : Local { my ($self,$c,$mensaje) = @_;

# Heredamos el mdulo como lo haramos con cualquier aplicacin CGI my $pdfFile = PDF::CreateSimple->new("root/reporte.pdf",undef,'LETTER'); # Pasamos algunos parametros (Esto no es catalyst, es perl) $pdfFile->drawText($mensaje,'Verdana',10,200,450,'black',3); $pdfFile->drawText('Generado con Catalyst','Verdana',10,200,400,'black',3); $pdfFile->drawImage('root/images/catalyst-logo.png',250,300); # esto no enva el pdf para descargar, sino que lo guarda en el disco $pdfFile->closeFile; # Ahora enviamos al navegador a que muestre el archivo recin guardado $c->res->redirect("/archivo.pdf");}Est respaldado por la gran cantidad de mdulos que hospeda cpan.

there's nothing magical about catalyst, it doesn't get in your way, it just dispatches urls to actions

Ventajas de su uso

Por supuesto, TIMTOWTDI

(There Is More Than One Way To Do It)

Instalacin

Paquetes en debian / ubuntu :

libcatalyst-perl

libcatalyst-modules-perl

Mdulos usando cpan:

Catalyst

El resto que se necesite.

Por ejemplo, en la shell: cpan CGI::FormBuilder

usar dh_make para convertir modulos de perl a paquetes debian y as instalarlos.

$ catalyst.pl proyecto

$ cd proyecto/

$ perl script/proyecto_server.pl

Creando un proyecto

Creamos proyecto

$ catalyst.pl proyecto

Nos cambiamos de directorio de trabajo al recien creado (nombre del proyecto)

$ cd proyecto

Corremos el servidor de pruebas

$ perl script/proyecto_server.pl

Estructura establecida de los directorios manteniendo un orden.

Creando controlador

perl script/sistap_create.pl controller unesco_area

lib/sistap/Controller/unesco_area.pm

package sistap::Controller::unesco_area;

use strict;use warnings;use base 'Catalyst::Controller';

sub index : Private { my ( $self, $c ) = @_;

$c->response->body('Hola mundo');}

sub saludo : Local { my ( $self, $c ) = @_;

$c->response->body('Hola mundo... de nuevo');}

1;http://localhost:3000/unesco_area/saludo

Controlador

Accin

Mtodos de despacho

Local (: Local {})

Reconoce el nombre de la accin como primer argumento del controlador.

Path (: Path('foo/bar') { })

Se especifica una ruta absoluta a despachar.

Global (: Global { })

Despacha el primer nivel (como si fuera controlador)

Private (: Private {} )

Especial para funciones reservadas en catalyst (default, index, begin, end, auto) , no es despachada por url.

sub saludo : Local { my ( $self, $c ) = @_; $c->res->body('dvst');}

Regex ( : Regex('^item(\d+)/orden(\d+)$') { } )

Despacha segn una expresin regular dada (en todo el sistema)

No usa ModRewrite para esto.

item4/orden243 es capturada con esa expresin.

LocalRegex ( : LocalRegex('^widget(\d+)$') { } )

Igual que Regex pero solo es interpretada en el controlador donde est definida.

widget23 es reconocido con la expresin del ejemplo.

Chained

Se realiza una cadea entre diferentes acciones

CaptureArgs() y Args()

Se combina con Chained para reconocer la cadena

Metodos de despacho

Chained / CaptureArgs() / Args()

sub wiki : PathPart('wiki') Chained('/') CaptureArgs(1) { my ( $self, $c, $page_name ) = @_; # carga la pgina de nombre $page_name y coloca el objeto en el stash $c->stash->{var1} = $page_name; }

sub rev : PathPart('rev') Chained('wiki') CaptureArgs(1) { my ( $self, $c, $revision_id ) = @_; # Usa el objeto de pgina que est en el stash y obtiene el nmero # de revisin $revision_id. $c->stash->{var2} = $revision_id ; }

sub view : PathPart Chained('rev') Args(0) { my ( $self, $c ) = @_; # Muestra la revisin de la pgina en pantalla,my $salida ;$salida = "Esta pantalla muestra la revision: " . $c->stash->{var2} ;$salida .= " de la pagina: " . $c->stash->{var1} ; $c->res->body($salida); }URL:http://localhost:3000/wiki/principal/rev/4/view

Salida por pantalla:
Esta pantalla muestra la revision: 4 de la pagina: principal

sub view : PathPart Chained('wiki') Args(0) { my ( $self, $c ) = @_; # Muestra la revisin de la pgina en pantalla,my $salida ;$salida = "Esta pantalla muestra la revision: " . $c->stash->{var2} ;$salida .= " de la pagina: " . $c->stash->{var1} ; $c->res->body($salida); }

Creando un modelo (DBIx::Class -> Catalyst::Model::DBIC::Schema)

Necesitamos esquema.
(archivo lib/sistapDB.pm)

package sistapDB;

=head1 NAME

sistapDB - DBIC Schema Class

=cut

# Nuetro esquema necesita heredar desde 'DBIx::Class::Schema'use base qw/DBIx::Class::Schema/;

# Se necesitan cargas las clases de modelo de base de datos ac__PACKAGE__->load_classes({sistapDB => [qw/unesco_areaunesco_subareaunesco_categoria/]});

1;

Creando un modelo

Se crea una clase por tabla

(archivo lib/sistapDB/unesco_area.pm)

usamos DBIx::Class::Schema::Loader

package sistapDB::unesco_area;

use base qw/DBIx::Class/;

# Se cargan componentes requeridos por DBIC__PACKAGE__->load_components(qw/PK::Auto Core/);

# Se asigna el nombre de la base de datos __PACKAGE__->table('sta_unesco_area');

# Se listan los campos de la tabla__PACKAGE__->add_columns(qw/id codigo nombre descripcion activo /);

# Se indica la llave primaria de la tabla__PACKAGE__->set_primary_key(qw/id/);

# Asignamos las relaciones __PACKAGE__->has_many( subareas => 'sistapDB::unesco_subarea','id_unesco_area');

1;

Creando un modelo

package DBIC::Model::sistapDB;

use strict;

use base 'Catalyst::Model::DBIC::Schema';

__PACKAGE__->config(

schema_class => 'sistapDB',

connect_info => [

'dbi:Pg:dbname=sistap',

'usuario',

'clave',

{ AutoCommit => 1 },

],

);

Resultado:
(Archivo: lib/sistap/Model/sistapDB)

Script helper:

.script/sistap_create.pl model sistapDB DBIC::Schema \

sistapDB dbi:Pg:dbname=sistap 'usuario' 'clave' '{ AutoCommit => 1 }'

Trabajando con relaciones

package sistapDB::unesco_area;#... Se hereda clase ; Carga de componentes ; nombre de la tabla ; nombre columnas ; llave primaria__PACKAGE__->add_columns(qw/id_area nombre/);

# empezamos a declarar las relaciones a nivel de ORM__PACKAGE__->has_many( subareas => 'sistapDB::unesco_subarea','id_area');package sistapDB::unesco_subarea;#... igual que arriba__PACKAGE__->add_columns(qw/id_subarea id_area nombre/);

# empezamos a declarar las relaciones a nivel de ORM__PACKAGE__->belongs_to( area => 'sistapDB::unesco_area','id_area');__PACKAGE__->has_many( categorias => 'sistapDB::unesco_subarea','id_subarea');package sistapDB::unesco_categoria;#... igual que arriba__PACKAGE__->add_columns(qw/id_categoria id_subarea nombre/);

# empezamos a declarar las relaciones a nivel de ORM__PACKAGE__->belongs_to( subarea => 'sistapDB::unesco_subarea','id_subarea');

Usando DBIC en el controlador

Mtodos ms comunes:

find (SELECT .. LIMIT 1) : Obtiene un (1) registro (hash) segn patrn de busqueda

$area = $c->model(sistapDB::unesco_area)->find(3);

$persona = c->model(sistapDB::personas)->find({ nombre => { ILIKE => '%javier%' }})

search (SELECT *) : Obtiene un arreglo de registros

@productos = $c->model(sistapDB::productos)->search({ codigo => 've' , tipo => 'abc' });

create (INSERT) : Crea un nuevo registro segn el hash pasado.

my $campos = { codigo => $c->req->param("codigo"), nombre => $c->req->param(nombre)};

$registro = $c->model(sistapDB::productos)->create($campos);

# al asignar la creacin del registro a una variable, se obtiene el ResourceSet de la operacin

$registro->id ; # se obtiene el id del registro recien insertado.

update: Actualiza el ResourceSet

$equipo = $c->model(sistapDB::equipos)->find(3);

$equipo->tipo(ups);

$equipo->dominio(administracion);

$equipo->update;

delete : Elimina los registros del resourceSet

$c->model(sistapDB::equipos)->search({tipo => 'ups'})->delete;

Paginador usando DBIC

Plantilla (Template Toolkit)

package sistap::Controller::esta;

sub pagina : Local {

my ( $self , $c ) = @_ ;

my $nroRegistros = $c->req->param("nroRegistros") || 10;

my $nroPagina = $c->req->param("nroPagina") || 1;

my $paginador = $c->model("sistapDB::instituciones")->search(undef,{

page => $nroPagina,

rows => $nroRegistros

}) ;

$c->stash->{registros} = $paginador ;

}

  • [% WHILE ( r = registro.next ) %]

  • [% r.nombre %]

    [% END %]

Nro pgina

Controlador

Vistas

TTSite

Template Toolkit

JSON

PHP

ClearSilver (yahoo, google)

...

Predefiniendo una vista.

Vistas
(TTSite -> Catalyst::Helper::View::TTSite)

./lib/config/

Configuracin de variables (colores, rutas predefinidas, etc) a ser usadas.

./lib/site

Plantillas fuentes

footer: Pie de pgina

header: Encabezado (h1 con nombre de pgina)

html: Esqueleto base (Incluye ttsite.css)

layout: Cuerpo (body) del documento.

wrapper: Quin se encarga de acoplarlos.

./src

Plantillas predefinidas.

.|-- lib| |-- config| | |-- col| | |-- main| | `-- url| `-- site| |-- footer| |-- header| |-- html| |-- layout| `-- wrapper`--- src |-- error.tt2 |-- message.tt2 |-- ttsite.css `-- welcome.tt2

perl script/sistap_create view TTSite TTSite

Vistas
(Template Toolkit)

perl script/sistap_create view TT TT

Por defecto, las plantillas se almacenan en root

$c->stash->{variable} && [% variable %]

Vistas
(JSON)

Catalyst::View::JSON

perl script/sistap_create view JSON JSON

my @estados = $c->model("sistapDB::paises")->find($id_pais)->estados(undef,{order_by => 'nombre'}) ;

$c->stash->{estados} = [map { { id_estado => $_->id_estado , nombre_estado => $_->nombre } } @estados ];

$c->forward('sistap::View::JSON');my @estados = $c->model("sistapDB::paises")->find($id_pais)->estados()->all ;

$c->stash->{estados} = @estados ;

$c->forward('sistap::View::JSON');

Vistas

Predefiniendo una vista

sistap.yml

Al trabajar con varias vistas, si no se especifica cual usar por defecto, podemos tener problemas.

---name: sistapdefault_view: TTauthentication: ...

Agregando mdulos (Catalyst::Plugin)

package sistap;

use strict;

use warnings;

use Catalyst::Runtime '5.70';

use Catalyst qw/

-Debug

ConfigLoader

Static::Simple

Authentication

Authentication::Store::DBIC

Authentication::Credential::Password

Authorization::Roles

Prototype

Dumper

Session

Session::Store::FastMmap

Session::State::Cookie

/;

our $VERSION = '0.01';

__PACKAGE__->config( name => 'sistap',

session => { flash_to_stash => 1 },

form => { messages => ':es_ES' }

);

__PACKAGE__->setup( qw/RequireSSL/ );

1;

lib/sistap.pm

-Debug

Modo verboso en consola cuando se usa servidor de pruebas.

ConfigLoader

Se usa para cargar informacin de sistap.yml

Static::Simple

Para que reconozca archivos estaticos (imagenes, css, js) y no trate despacha las rutas si hay coincidencia.

Authentication/Autorization*

Autenticacin (Quin tiene acceso?)

Autorizacin (de qu tiene acceso?)

Prototype

Ejectos integrados de script.aculo.us

Dumper

uso de Data::Dumper para obtener estructuras completas de data.

Session*

Manejo de sessiones.

Generacin de formularios
Catalyst::Controller::FormBuilder

Generacin de formularios

Se compone en varios archivos para mayor mantenimiento y abstrabcin de conceptos.

Detalle de formulario

root/forms/nombre/comun.fb

Controlador

lib/sistap/Controller/nombre.pm

Plantilla

root/src/nombre/comun.tt

FormBuilder en Catalyst (CGI::FormBuilder)

Descripcin del formulario (root/forms/unesco_subarea/comun.fb)

name: unesco_subarea

method: post

action: /unesco_subarea/operaciones

fields:

tOperacion:

type: hidden

id:

id: hdn_id

type: hidden

id_unesco_area:

label : Area

type: select

id: txt_id_unesco_area

disabled : disabled

autocomplete: off

codigo:

id: txt_codigo

disabled : disabled

autocomplete: off

required : 1

nombre:

id: txt_nombre

disabled : disabled

autocomplete: off

required: 1

validate : NAME

Formato yaml.

Usen espacios, no tabs.

Definicin de elementos y sus atributos.

Validaciones (Cliente y Servidor)*

Facilmente aplicable a plantillas.

* la validacin absoluta debera aplicarse a nivel de base de datos

FormBuilder en Catalyst (CGI::FormBuilder)

Controlador (lib/sistap/Controller/unesco_subarea)

package sistap::Controller::unesco_subarea;

use strict;

use warnings;

use base 'Catalyst::Controller::FormBuilder';

...

sub principal : Path('/mantenimiento/unesco_subarea') Form('unesco_subarea/comun') {

my ($self, $c) = @_ ;

my $form = $self->formbuilder;

$form->field( name => 'id_unesco_area',

options => [ map {

{ $_->id_area => $_->nombre }

} $c->model(sistapDB::unesco_area)->all ]

);

if ($form->submitted && $form->validate){

$c->model(sistapDB::unesco_subarea)->create($form->fields) ;

}

}

FormBuilder en Catalyst (CGI::FormBuilder)

Plantilla (root/src/unesco_subarea/comun.tt)

[% FormBuilder.render %]

[% FormBuilder.start -%]

[% formFuilder.jshead %]

[% FormBuilder.field.tOperacion.field -%]

[% FormBuilder.field.id_institucion.field -%]

[% FormBuilder.field.nombre.label -%]

[% FormBuilder.field.nombre.field -%]

[% FormBuilder.field.siglas.label -%]

[% FormBuilder.field.siglas.field -%]

[% FormBuilder.end -%]

Variables de session

Uso de sesiones

Agregar plugin de session

store

cookie (la data)

bd

archivo

state

url (QueryString)

Variable oculta ()

cookie (solo id nico)

Variables de session slo para el usuario que ejecuta la accin.

$c->session->{id} = hey ;

[% c.session.id %]

delete($c->session->{id}) ;

$c->session->{id} = undef ;

Variable de session para todos los usuarios

$c->store_session_data(key,value)

$c->store_session_data(color,azul)

$c->get_session_data(key)

$c->get_session_data(color)

$c->delete_session_data(key)

uso de Flash
(BTW: nada que ver con adobe )

Debe estar cargado plugin de sesion (Catalyst::Plugin::Session)

lib/sistap.pm

PACKAGE__->config(

name => 'sistap',

session => {

flash_to_stash => 1

}

);

Controlador

$c->flash->{error} = Pagina invalida

Plantilla (TT)

[% error %]

Autenticacin / Autorizacin

Autenticacin y autorizacin

---name: sistapdefault_view: TTauthentication: dbic: # nombre del esquema que contiene la informacion de los usuarios user_class: sistapDB::usuarios

# Este es el nombre del campo en la tabla de usuarios, que contiene el nombre del usuario user_field: username

# Este es el nombre del campo en la tabla de usuarios, que contiene la clave del usuario password_field: password

# Habilitar claves cifradas password_type: hashed

# Usamos el algoritmo de cifrado SHA-1 password_hash_type: SHA-1

authorization: dbic: # nombre del esquema que contiene la informacion de los roles del usuario role_class: sistapDB::roles

# Este es el nombre del campo en la tabla de de roles, que contiene los diferentes roles role_field: rol

# The name of the accessor used to map a role to the users who have this role # nombre de la relacin asociada a la tabla de usuarios_roles role_rel: map_user_role

# nombre del campo en la tabla de relacin usuarios_roles que referencia al usuario (id) user_role_user_field: usuario_id

Autenticacin y autorizacin

Configuracion: lib/sistap.pm

__PACKAGE__->config( name => 'sistap',

session => {

expires => 2400,

storage => '/tmp/session',

},

);

Acciones

$c->login($username, $password) ;

$c->user_exists ;

$c->user->ciUsuario ;

$c->check_user_roles('admin') ;

$c->logout ;

jQuery

Qu es jQuery?

Framework de JavaScript

Selectores de CSS3.

Manipulacin de eventos.

Ajax.

Gran cantidad de plugins.

Tabs.

Menues.

Formularios.

Dialogos.

Drag and Drop.

etc ( http://jquery.com/plugins/ )

jQuery

jQuery.noConflict();

jQuery(function(){

// El cdigo a ejecutarse cuando se cargue todo el documento ac

}

// ac tambin puede haber cdigo, pero no si se disparar an cuando

// el documento no est cargado

jQuery: Selectores

Bsicamente jQuery(selector CSS o xpath)

jQuery("#txt_pais").val(jQuery("#modal_pais :selected").text())

Antes: document.getElementById(txt_pais).value = document.getElementById("modal_pais").options[document.getElementById("modal_pais").selectedIndex].text

jQuery(".jd_menu li ul li ul").parent().addClass("flecha_menu");

Antes: Posiblemente usara un id por cada elemento y sabiendo quin merece la imagen, se la asigno, sino, del lado del servidor.

jQuery("table.cebra tr:even").addClass("resaltado");

Antes: Si se construye la tabla de forma dinmica (php, perl, python, etc), controlar el nmero del registro y asignar la clase correspondiente.

jQuery("input[@type=text]:visible").eq(0).focus()

Antes: Seguro hara lo mismo pero a pie, pasar por todo el fomulario buscando los elementos visibles y luego situarme en el primer elemento.

Ajax
(ahah)

Ajax
(ahah)

Crear vista de JSON.

perl script/sistap_create view JSON JSON

La informacin a enviar como respuesta est en el stash.

$c->stash->{salida} = hey;

jQuery captura los datos.

jQuery.getJSON( url , param , function(jsonData){

if (jsonData.salida == hey ){

alert(fino);

}else{

alert(error al obtener la data);

}

})

Ajax
(JSON)

my $id_pais = $c->req->param(pais_id);my @estados = $c->model("sistapDB::paises")->find($id_pais)->estados(undef,{order_by => 'nombre'}) ;

$c->stash->{estados} = [map { { id_estado => $_->id_estado , nombre_estado => $_->nombre } } @estados ];

$c->forward('sistap::View::JSON');var param = new Object();

param = {pais_id : 3} ;

jQuery.getJSON( [% c.uri_for('controlador/accion/') %] , param , function(jsonData){

if (jsonData.estados){

for (i= 0 ; jsonData.estados.lenght ; i++){

// tengo jsonData.estados[i].id_estado y jsonData.estados[i].nombre_estado

}

}else{

console.info(hubo un error al traer la data);

// incluso se puede capturar si se acab el tiempo de sesin

// de usuario segn respuesta y se recarga la pgina.

}

})

jQuery.getJSON( url , parametros , function(jsonData){ // trabajamos con el resultado... jsonData });

jQuery: plugins

Tabs

http://stilbuero.de/jquery/tabs/

menu

http://jdsharp.us/jQuery/plugins/jdMenu/

Thickbox

http://jquery.com/demo/thickbox/

Form

http://www.malsup.com/jquery/form/

Interfaces (interfaces es para para jQuery, lo que script.aculo.us es para prototype)

http://interface.eyecon.ro/

Muchos mas.

http://jquery.com/plugins/

jQuery: plugin TABS

jQuery(function(){jQuery('#menu-subvencion').tabs({ fxFade : true , fxSpeed : 'fast' , remote: true });})

  • Datos

    generales

  • Resumen

jQuery: plugin jdMenu

$(function(){

$('ul.jd_menu').jdMenu();

});

  • Item A

    • Item 1
    • Item 2
  • Item B

jQuery: plugin thickbox

Usuario :

Clave :

Depuracin

Depuracin

javascript (firebug) : console.info()

Depuracin

Catalyst : $c->log->debug()

Depuracin

DBIC: export DBIC_TRACE=1=/tmp/salida.txt

Consejos

Usar uri_for (en las plantillas y controlador).

Enlace

$c->res->redirect($c->uri_for('/a/b/c'));

Usar relaciones en ORM (DBIC).

Usar Template Toolkit para generar maestros.

Usar Flash + redirect para mensajes a usuario.

Usar Ajax solo cuando sea justificado. (No AJfiXiar el sitio)

Usar Unicode

BD (UTF-8)

Servidor web (apache: AddDefaultCharset utf8)

Archivo (Usar un editor que lo soporte, como vim )

Documento (html: )

Usar la funcin jQuery en vez de la funcin annima ($)

jQuery.noConflict()

Proyectos libres nacionales desarrollados usando Catalyst (Que conozco hasta ahora)

Debian::Package::HTML

http://search.cpan.org/~bureado/Debian-Package-HTML-0.1/lib/Debian/Package/HTML.pm

PUBuilder

http://blog.bureado.com.ve/?p=307

Sistap:

http://sistemas.fsl.fundacite-merida.gob.ve/projects/sistap

TEGZ:

http://sistemas.fsl.fundacite-merida.gob.ve/projects/tegz

Preguntas?

Gracias por su atencin

Pulse para editar los formatos del texto del esquema

Segundo nivel del esquema

Tercer nivel del esquema

Cuarto nivel del esquema

Quinto nivel del esquema

Sexto nivel del esquema

Sptimo nivel del esquema

Octavo nivel del esquema

Noveno nivel del esquema