Desarrollo de aplicaciones web usando Catalyst y jQuery

2,920 views

Published on

Ponencia presentada en las terceras jornadas de software libre realizadas en el iuta de maracay el sábado 3 de noviembre 2007

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
2,920
On SlideShare
0
From Embeds
0
Number of Embeds
33
Actions
Shares
0
Downloads
43
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Desarrollo de aplicaciones web usando Catalyst y jQuery

  1. 1. Javier E. Pérez P. Noviembre 2007 Desarrollo de aplicaciones web usando Catalyst y jQuery
  2. 2. Puntos a tratar <ul><li>¿Qué es Catalyst? </li></ul><ul><li>Ventajas de su uso. </li></ul><ul><li>Requisitos de instalación. </li></ul><ul><li>Creando un proyecto. </li></ul><ul><li>Estructura de proyecto. </li></ul><ul><li>Creación de: Controlador, Modelo, Vista. </li></ul><ul><li>Agregando módulos. </li></ul><ul><li>Conexión a base de datos (DBIC). </li></ul><ul><li>Trabajando con plantillas (TT, TTSite) </li></ul><ul><li>Trabajando con formularios (FormBuilder). </li></ul><ul><li>Uso de sessiones. </li></ul><ul><li>Autorización, autenticación. </li></ul><ul><li>Depuración. </li></ul><ul><li>Consejos. </li></ul><ul><li>Proyectos nacionales desarrollados usando catalyst. </li></ul>
  3. 3. ¿Qué es Catalyst? <ul><li>Framework Web escrito usando perl. </li></ul><ul><li>MVC. </li></ul><ul><li>Unicode. </li></ul><ul><li>Servidor de pruebas integrado. </li></ul>
  4. 4. Metodología MVC <ul><ul><li>Modelo </li></ul></ul><ul><ul><ul><li>De donde se almacenan los datos. </li></ul></ul></ul><ul><ul><ul><li>Generalmente base de datos. </li></ul></ul></ul><ul><ul><li>Vista </li></ul></ul><ul><ul><ul><li>La presentación de los datos. </li></ul></ul></ul><ul><ul><ul><li>HTML, JSON, RSS, XML, etc. </li></ul></ul></ul><ul><ul><li>Controlador </li></ul></ul><ul><ul><ul><li>Quién maneja las transacciones entre la solicitud del usuario, el proceso y salida de información. </li></ul></ul></ul><ul><ul><ul><li>Catalyst itself </li></ul></ul></ul>
  5. 5. Ventajas de su uso
  6. 6. Ventajas de su uso <ul><li>Despacho del URL, se trabaja por segmentos en vez de querystring's </li></ul><ul><li>Instalación sencilla. </li></ul><ul><li>Estructura establecida de los directorios manteniendo un orden. </li></ul><ul><li>Está respaldado por la gran cantidad de módulos que hospeda cpan. </li></ul><ul><ul><li>Formularios </li></ul></ul><ul><ul><li>ORM's </li></ul></ul><ul><ul><li>Reportes </li></ul></ul><ul><ul><li>i18n </li></ul></ul><ul><ul><li>autenticatión, autorización. </li></ul></ul><ul><ul><li>etc. </li></ul></ul>
  7. 7. Ventajas de su uso <ul><li>Despacho del URL, se trabaja basado en segmentos en vez de querystring's. </li></ul>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)
  8. 8. <ul><li>Está respaldado por la gran cantidad de módulos que hospeda cpan. </li></ul>“ there's nothing magical about catalyst, it doesn't get in your way, it just dispatches urls to actions” Ventajas de su uso use PDF::CreateSimple; sub pdf : Local { my ($self,$c,$mensaje) = @_; # Heredamos el módulo como lo haríamos con cualquier aplicación CGI my $pdfFile = PDF::CreateSimple->new(&quot;root/reporte.pdf&quot;,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 envía el pdf para descargar, sino que lo guarda en el disco $pdfFile->closeFile; # Ahora enviamos al navegador a que muestre el archivo recién guardado $c->res->redirect(&quot;/archivo.pdf&quot;); }
  9. 9. <ul><ul><li>Por supuesto, TIMTOWTDI </li></ul></ul><ul><ul><li>(There Is More Than One Way To Do It) </li></ul></ul>
  10. 10. Instalación <ul><li>Paquetes en debian / ubuntu : </li></ul><ul><ul><li>libcatalyst-perl </li></ul></ul><ul><ul><li>libcatalyst-modules-perl </li></ul></ul><ul><li>Módulos usando cpan: </li></ul><ul><ul><li>Catalyst </li></ul></ul><ul><ul><li>El resto que se necesite. </li></ul></ul><ul><ul><ul><li>Por ejemplo, en la shell: cpan CGI::FormBuilder </li></ul></ul></ul><ul><ul><ul><li>ó usar dh_make para convertir modulos de perl a paquetes debian y así instalarlos. </li></ul></ul></ul><ul><ul><ul><li>$ catalyst.pl proyecto </li></ul></ul></ul><ul><ul><ul><li>$ cd proyecto/ </li></ul></ul></ul><ul><ul><ul><li>$ perl script/proyecto_server.pl </li></ul></ul></ul>
  11. 11. Creando un proyecto <ul><li>Creamos proyecto </li></ul><ul><ul><li>$ catalyst.pl proyecto </li></ul></ul><ul><li>Nos cambiamos de directorio de trabajo al recien creado (nombre del proyecto) </li></ul><ul><ul><li>$ cd proyecto </li></ul></ul><ul><li>Corremos el servidor de pruebas </li></ul><ul><ul><li>$ perl script/proyecto_server.pl </li></ul></ul>
  12. 12. <ul><li>Estructura establecida de los directorios manteniendo un orden. </li></ul>
  13. 13. Creando controlador <ul><li>perl script/sistap_create.pl controller unesco_area </li></ul><ul><li>lib/sistap/Controller/unesco_area.pm </li></ul>http://localhost:3000/ unesco_area / saludo <ul><li>Controlador </li></ul><ul><li>Acción </li></ul>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;
  14. 14. Métodos de despacho <ul><li>Local (: Local {}) </li></ul><ul><ul><li>Reconoce el nombre de la acción como primer argumento del controlador. </li></ul></ul><ul><li>Path (: Path('foo/bar') { }) </li></ul><ul><ul><li>Se especifica una ruta absoluta a despachar. </li></ul></ul><ul><li>Global (: Global { }) </li></ul><ul><ul><li>Despacha el primer nivel (como si fuera controlador) </li></ul></ul><ul><li>Private (: Private {} ) </li></ul><ul><ul><li>Especial para funciones reservadas en catalyst (default, index, begin, end, auto) , no es despachada por url. </li></ul></ul><ul><li>Regex ( : Regex('^item(d+)/orden(d+)$') { } ) </li></ul><ul><ul><li>Despacha según una expresión regular dada (en todo el sistema) </li></ul></ul><ul><ul><li>No usa ModRewrite para esto. </li></ul></ul><ul><ul><li>item4/orden243 es capturada con esa expresión. </li></ul></ul><ul><li>LocalRegex ( : LocalRegex('^widget(d+)$') { } ) </li></ul><ul><ul><li>Igual que “Regex” pero solo es interpretada en el controlador donde está definida. </li></ul></ul><ul><ul><li>widget23 es reconocido con la expresión del ejemplo. </li></ul></ul><ul><li>Chained </li></ul><ul><ul><li>Se realiza una cadea entre diferentes acciones </li></ul></ul><ul><li>CaptureArgs() y Args() </li></ul><ul><ul><li>Se combina con Chained para reconocer la cadena </li></ul></ul>sub saludo : Local { my ( $self, $c ) = @_; $c->res->body('dvst'); }
  15. 15. Metodos de despacho <ul><li>Chained / CaptureArgs() / Args() </li></ul>sub wiki : PathPart('wiki') Chained('/') CaptureArgs(1) { my ( $self, $c, $page_name ) = @_; # carga la página 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 página que está en el stash y obtiene el número # de revisión $revision_id. $c->stash->{var2} = $revision_id ; } sub view : PathPart Chained('rev') Args(0) { my ( $self, $c ) = @_; # Muestra la revisión de la página en pantalla, my $salida ; $salida = &quot;Esta pantalla muestra la revision: &quot; . $c->stash->{var2} ; $salida .= &quot; de la pagina: &quot; . $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 revisión de la página en pantalla, my $salida ; $salida = &quot;Esta pantalla muestra la revision: &quot; . $c->stash->{var2} ; $salida .= &quot; de la pagina: &quot; . $c->stash->{var1} ; $c->res->body($salida); }
  16. 16. Creando un modelo (DBIx::Class -> Catalyst::Model::DBIC::Schema) <ul><li>Necesitamos esquema. (archivo lib/sistapDB.pm) </li></ul>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_area unesco_subarea unesco_categoria /] }); 1 ;
  17. 17. Creando un modelo <ul><li>Se crea una clase por tabla </li></ul><ul><ul><li>(archivo lib/sistapDB/unesco_area.pm) </li></ul></ul><ul><li>ó usamos DBIx::Class::Schema::Loader </li></ul>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 ;
  18. 18. Creando un modelo <ul><ul><li>Resultado : (Archivo: lib/sistap/Model/sistapDB) </li></ul></ul><ul><ul><li>Script helper : </li></ul></ul><ul><ul><li>.script/sistap_create.pl model sistapDB DBIC::Schema </li></ul></ul><ul><ul><li>sistapDB dbi:Pg:dbname=sistap 'usuario' 'clave' '{ AutoCommit => 1 } ' </li></ul></ul><ul><ul><li>package DBIC::Model:: sistapDB ; </li></ul></ul><ul><ul><li>use strict; </li></ul></ul><ul><ul><li>use base 'Catalyst::Model::DBIC::Schema'; </li></ul></ul><ul><ul><li>__PACKAGE__->config( </li></ul></ul><ul><ul><li>schema_class => ' sistapDB ', </li></ul></ul><ul><ul><li>connect_info => [ </li></ul></ul><ul><ul><li>'dbi:Pg:dbname=sistap', </li></ul></ul><ul><ul><li>'usuario', </li></ul></ul><ul><ul><li>'clave', </li></ul></ul><ul><ul><li>{ AutoCommit => 1 }, </li></ul></ul><ul><ul><li>], </li></ul></ul><ul><ul><li>); </li></ul></ul>
  19. 19. 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 ');
  20. 20. Usando DBIC en el controlador <ul><ul><li>Métodos más comunes: </li></ul></ul><ul><ul><li>find ( SELECT .. LIMIT 1 ) : Obtiene un (1) registro (hash) según patrón de busqueda </li></ul></ul><ul><ul><li>$area = $c->model(“sistapDB::unesco_area”)->find(3); </li></ul></ul><ul><ul><li>$persona = c->model(“sistapDB::personas”)->find({ nombre => { ILIKE => '%javier%' }}) </li></ul></ul><ul><ul><li>search (SELECT *) : Obtiene un arreglo de registros </li></ul></ul><ul><ul><li>@productos = $c->model(“sistapDB::productos”)->search({ codigo => 've' , tipo => 'abc' }); </li></ul></ul><ul><ul><li>create (INSERT) : Crea un nuevo registro según el hash pasado. </li></ul></ul><ul><ul><li>my $campos = { codigo => $c->req->param(&quot;codigo&quot;), nombre => $c->req->param(“nombre”)}; </li></ul></ul><ul><ul><li>$registro = $c->model(“sistapDB::productos”)->create($campos); </li></ul></ul><ul><ul><li># al asignar la creación del registro a una variable, se obtiene el ResourceSet de la operación </li></ul></ul><ul><ul><li>$registro->id ; # se obtiene el id del registro recien insertado. </li></ul></ul><ul><ul><li>update : Actualiza el ResourceSet </li></ul></ul><ul><ul><li>$equipo = $c->model(“sistapDB::equipos”)->find(3); </li></ul></ul><ul><ul><li>$equipo->tipo(“ups”); </li></ul></ul><ul><ul><li>$equipo->dominio(“administracion”); </li></ul></ul><ul><ul><li>$equipo->update; </li></ul></ul><ul><ul><li>delete : Elimina los registros del resourceSet </li></ul></ul><ul><ul><li>$c->model(“sistapDB::equipos”)->search({tipo => 'ups'})->delete; </li></ul></ul>
  21. 21. Paginador usando DBIC Plantilla (Template Toolkit) Controlador <ul><ul><li>package sistap::Controller::esta; </li></ul></ul><ul><ul><li>sub pagina : Local { </li></ul></ul><ul><ul><li>my ( $self , $c ) = @_ ; </li></ul></ul><ul><ul><li>my $nroRegistros = $c->req ->param( &quot;nroRegistros&quot; ) || 10; </li></ul></ul><ul><ul><li>my $nroPagina = $c->req ->param( &quot;nroPagina&quot; ) || 1; </li></ul></ul><ul><ul><li>my $paginador = $c->model ( &quot;sistapDB::instituciones&quot; )->search(undef,{ </li></ul></ul><ul><ul><li>page => $nroPagina, </li></ul></ul><ul><ul><li>rows => $nroRegistros </li></ul></ul><ul><ul><li>}) ; </li></ul></ul><ul><ul><li>$c->stash->{registros} = $paginador ; </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li><ul> </li></ul></ul><ul><ul><li>[% WHILE ( r = registro.next ) %] </li></ul></ul><ul><ul><li><li> [% r.nombre %] </li> </li></ul></ul><ul><ul><li>[% END %] </li></ul></ul><ul><ul><li></ul> </li></ul></ul><ul><ul><li><form action=”[% c.uri_for('/esta/pagina') %]”> </li></ul></ul><ul><ul><li><label for=”nro_pagina”>Nro página</label> </li></ul></ul><ul><ul><li><input type=”text” id=”nro_pagina” name=”nroPagina”> </li></ul></ul><ul><ul><li><input type=”submit” value=”Ir a pagina”> </li></ul></ul><ul><ul><li></form> </li></ul></ul>
  22. 22. Vistas <ul><li>TTSite </li></ul><ul><li>Template Toolkit </li></ul><ul><li>JSON </li></ul><ul><li>PHP </li></ul><ul><li>ClearSilver (yahoo, google) </li></ul><ul><li>... </li></ul><ul><li>Predefiniendo una vista. </li></ul>
  23. 23. Vistas (TTSite -> Catalyst::Helper::View::TTSite) <ul><li>./lib/config/ </li></ul><ul><ul><li>Configuración de variables (colores, rutas predefinidas, etc) a ser usadas. </li></ul></ul><ul><li>./lib/site </li></ul><ul><ul><li>Plantillas fuentes </li></ul></ul><ul><ul><ul><li>footer : Pie de página </li></ul></ul></ul><ul><ul><ul><li>heade r: Encabezado (h1 con nombre de página) </li></ul></ul></ul><ul><ul><ul><li>html : Esqueleto base (Incluye ttsite.css) </li></ul></ul></ul><ul><ul><ul><li>layout : Cuerpo (body) del documento. </li></ul></ul></ul><ul><ul><ul><li>wrapper : Quién se encarga de acoplarlos. </li></ul></ul></ul><ul><li>./src </li></ul><ul><ul><li>Plantillas predefinidas. </li></ul></ul><ul><ul><li>perl script/sistap_create view TTSite TTSite </li></ul></ul>. |-- lib | |-- config | | |-- col | | |-- main | | `-- url | `-- site | |-- footer | |-- header | |-- html | |-- layout | `-- wrapper `--- src |-- error.tt2 |-- message.tt2 |-- ttsite.css `-- welcome.tt2
  24. 24. Vistas (Template Toolkit) <ul><li>perl script/sistap_create view TT TT </li></ul><ul><li>Por defecto, las plantillas se almacenan en root </li></ul><ul><li>$c->stash->{variable} && [% variable %] </li></ul>
  25. 25. Vistas (JSON) <ul><li>Catalyst::View::JSON </li></ul><ul><li>perl script/sistap_create view JSON JSON </li></ul>my @estados = $c->model ( &quot;sistapDB::paises&quot; )->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 ( &quot;sistapDB::paises&quot; )->find($id_pais)->estados()->all ; $c->stash ->{estados} = @estados ; $c->forward (' sistap::View::JSON ');
  26. 26. Vistas <ul><li>Predefiniendo una vista </li></ul><ul><ul><li>sistap.yml </li></ul></ul><ul><li>Al trabajar con varias vistas, si no se especifica cual usar por defecto, podemos tener problemas. </li></ul>--- name: sistap default_view: TT authentication: ...
  27. 27. Agregando módulos (Catalyst::Plugin) lib/sistap.pm <ul><ul><li>package sistap; </li></ul></ul><ul><ul><li>use strict; </li></ul></ul><ul><ul><li>use warnings; </li></ul></ul><ul><ul><li>use Catalyst::Runtime '5.70'; </li></ul></ul><ul><ul><li>use Catalyst qw/ </li></ul></ul><ul><ul><li>-Debug </li></ul></ul><ul><ul><li>ConfigLoader </li></ul></ul><ul><ul><li>Static::Simple </li></ul></ul><ul><ul><li>Authentication </li></ul></ul><ul><ul><li>Authentication::Store::DBIC </li></ul></ul><ul><ul><li>Authentication::Credential::Password </li></ul></ul><ul><ul><li>Authorization::Roles </li></ul></ul><ul><ul><li>Prototype </li></ul></ul><ul><ul><li>Dumper </li></ul></ul><ul><ul><li>Session </li></ul></ul><ul><ul><li>Session::Store::FastMmap </li></ul></ul><ul><ul><li>Session::State::Cookie </li></ul></ul><ul><ul><li>/; </li></ul></ul><ul><ul><li>our $VERSION = '0.01'; </li></ul></ul><ul><ul><li>__PACKAGE__->config ( name => 'sistap', </li></ul></ul><ul><ul><li>session => { flash_to_stash => 1 }, </li></ul></ul><ul><ul><li>form => { messages => ':es_ES' } </li></ul></ul><ul><ul><li>); </li></ul></ul><ul><ul><li>__PACKAGE__->setup ( qw/RequireSSL/ ); </li></ul></ul><ul><ul><li>1; </li></ul></ul><ul><ul><li>-Debug </li></ul></ul><ul><ul><ul><li>Modo verboso en consola cuando se usa servidor de pruebas. </li></ul></ul></ul><ul><ul><li>ConfigLoader </li></ul></ul><ul><ul><ul><li>Se usa para cargar información de sistap.yml </li></ul></ul></ul><ul><ul><li>Static::Simple </li></ul></ul><ul><ul><ul><li>Para que reconozca archivos estaticos (imagenes, css, js) y no trate despacha las rutas si hay coincidencia. </li></ul></ul></ul><ul><ul><li>Authentication/Autorization* </li></ul></ul><ul><ul><ul><li>Autenticación (¿Quién tiene acceso?) </li></ul></ul></ul><ul><ul><ul><li>Autorización (¿de qué tiene acceso?) </li></ul></ul></ul><ul><ul><li>Prototype </li></ul></ul><ul><ul><ul><li>Ejectos integrados de script.aculo.us </li></ul></ul></ul><ul><ul><li>Dumper </li></ul></ul><ul><ul><ul><li>uso de Data::Dumper para obtener estructuras completas de data. </li></ul></ul></ul><ul><ul><li>Session* </li></ul></ul><ul><ul><ul><li>Manejo de sessiones. </li></ul></ul></ul>
  28. 28. Generación de formularios Catalyst::Controller::FormBuilder
  29. 29. Generación de formularios <ul><li>Se compone en varios archivos para mayor mantenimiento y abstrabción de conceptos. </li></ul><ul><ul><li>Detalle de formulario </li></ul></ul><ul><ul><ul><li>root/forms/nombre/comun.fb </li></ul></ul></ul><ul><ul><li>Controlador </li></ul></ul><ul><ul><ul><li>lib/sistap/Controller/nombre.pm </li></ul></ul></ul><ul><ul><li>Plantilla </li></ul></ul><ul><ul><ul><li>root/src/nombre/comun.tt </li></ul></ul></ul>
  30. 30. FormBuilder en Catalyst (CGI::FormBuilder) Descripción del formulario (root/forms/unesco_subarea/comun.fb) <ul><li>Formato yaml. </li></ul><ul><li>Usen espacios, no tabs. </li></ul><ul><li>Definición de elementos y sus atributos. </li></ul><ul><li>Validaciones (Cliente y Servidor) * </li></ul><ul><li>Facilmente aplicable a plantillas. </li></ul>* la validación absoluta debería aplicarse a nivel de base de datos <ul><ul><li>name: unesco_subarea </li></ul></ul><ul><ul><li>method: post </li></ul></ul><ul><ul><li>action: /unesco_subarea/operaciones </li></ul></ul><ul><ul><li>fields: </li></ul></ul><ul><ul><li>tOperacion: </li></ul></ul><ul><ul><li>type: hidden </li></ul></ul><ul><ul><li>id: </li></ul></ul><ul><ul><li>id: hdn_id </li></ul></ul><ul><ul><li>type: hidden </li></ul></ul><ul><ul><li>id_unesco_area: </li></ul></ul><ul><ul><li>label : Area </li></ul></ul><ul><ul><li>type: select </li></ul></ul><ul><ul><li>id: txt_id_unesco_area </li></ul></ul><ul><ul><li>disabled : disabled </li></ul></ul><ul><ul><li>autocomplete: off </li></ul></ul><ul><ul><li>codigo: </li></ul></ul><ul><ul><li>id: txt_codigo </li></ul></ul><ul><ul><li>disabled : disabled </li></ul></ul><ul><ul><li>autocomplete: off </li></ul></ul><ul><ul><li>required : 1 </li></ul></ul><ul><ul><li>nombre: </li></ul></ul><ul><ul><li>id: txt_nombre </li></ul></ul><ul><ul><li>disabled : disabled </li></ul></ul><ul><ul><li>autocomplete: off </li></ul></ul><ul><ul><li>required: 1 </li></ul></ul><ul><ul><li>validate : NAME </li></ul></ul>
  31. 31. FormBuilder en Catalyst (CGI::FormBuilder) Controlador (lib/sistap/Controller/unesco_subarea) <ul><ul><li>package sistap::Controller::unesco_subarea; </li></ul></ul><ul><ul><li>use strict; </li></ul></ul><ul><ul><li>use warnings; </li></ul></ul><ul><ul><li>use base 'Catalyst::Controller ::FormBuilder '; </li></ul></ul><ul><ul><li>... </li></ul></ul><ul><ul><li>sub principal : Path('/mantenimiento/unesco_subarea') Form('unesco_subarea/comun') { </li></ul></ul><ul><ul><li>my ($self, $c) = @_ ; </li></ul></ul><ul><ul><li>my $form = $self->formbuilder; </li></ul></ul><ul><ul><li>$form->field( name => 'id_unesco_area', </li></ul></ul><ul><ul><li>options => [ map { </li></ul></ul><ul><ul><li>{ $_->id_area => $_->nombre } </li></ul></ul><ul><ul><li>} $c->model(“sistapDB::unesco_area”)->all ] </li></ul></ul><ul><ul><li>); </li></ul></ul><ul><ul><li>if ($form->submitted && $form->validate){ </li></ul></ul><ul><ul><li>$c->model(“sistapDB::unesco_subarea”)->create($form->fields) ; </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul>
  32. 32. FormBuilder en Catalyst (CGI::FormBuilder) Plantilla (root/src/unesco_subarea/comun.tt) ó <ul><ul><li>[% FormBuilder.render %] </li></ul></ul><ul><ul><li>[% FormBuilder.start -%] </li></ul></ul><ul><ul><li>[% formFuilder.jshead %] </li></ul></ul><ul><ul><li><div id=&quot;form&quot;> </li></ul></ul><ul><ul><li>[% FormBuilder.field.tOperacion.field -%] </li></ul></ul><ul><ul><li>[% FormBuilder.field.id_institucion.field -%] </li></ul></ul><ul><ul><li><table> </li></ul></ul><ul><ul><li><tr> </li></ul></ul><ul><ul><li><td> [% FormBuilder.field.nombre.label -%]</td> </li></ul></ul><ul><ul><li><td> [% FormBuilder.field.nombre.field -%]</td> </li></ul></ul><ul><ul><li><td> [% FormBuilder.field.siglas.label -%]</td> </li></ul></ul><ul><ul><li><td> [% FormBuilder.field.siglas.field -%]</td> </li></ul></ul><ul><ul><li></tr> </li></ul></ul><ul><ul><li><tr> </li></ul></ul><ul><ul><li><td colspan=”2”><input type=”submit” value=”enviar”> </td> </li></ul></ul><ul><ul><li></tr> </li></ul></ul><ul><ul><li></table> </li></ul></ul><ul><ul><li>[% FormBuilder.end -%] </li></ul></ul>
  33. 33. Variables de session
  34. 34. Uso de sesiones <ul><li>Agregar plugin de session </li></ul><ul><ul><li>store </li></ul></ul><ul><ul><ul><li>cookie (la data) </li></ul></ul></ul><ul><ul><ul><li>bd </li></ul></ul></ul><ul><ul><ul><li>archivo </li></ul></ul></ul><ul><ul><li>state </li></ul></ul><ul><ul><ul><li>url (QueryString) </li></ul></ul></ul><ul><ul><ul><li>Variable oculta () </li></ul></ul></ul><ul><ul><ul><li>cookie (solo id único) </li></ul></ul></ul><ul><li>Variables de session sólo para el usuario que ejecuta la acción. </li></ul><ul><ul><li>$c->session->{id} = “hey” ; </li></ul></ul><ul><ul><li>[% c.session.id %] </li></ul></ul><ul><ul><li>delete($c->session->{id}) ; </li></ul></ul><ul><ul><li>$c->session->{id} = undef ; </li></ul></ul><ul><li>Variable de session para todos los usuarios </li></ul><ul><ul><li>$c->store_session_data(key,value) </li></ul></ul><ul><ul><li>$c->store_session_data(“color”,”azul”) </li></ul></ul><ul><ul><li>$c->get_session_data(key) </li></ul></ul><ul><ul><li>$c->get_session_data(“color”) </li></ul></ul><ul><ul><li>$c->delete_session_data(key) </li></ul></ul>
  35. 35. uso de Flash (BTW: nada que ver con adobe ™ ) <ul><ul><li>Debe estar cargado plugin de sesion ( Catalyst::Plugin::Session ) </li></ul></ul><ul><ul><li>lib/sistap.pm </li></ul></ul><ul><ul><li>PACKAGE__->config( </li></ul></ul><ul><ul><ul><li>name => 'sistap', </li></ul></ul></ul><ul><ul><ul><li>session => { </li></ul></ul></ul><ul><ul><ul><ul><li>flash_to_stash => 1 </li></ul></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>); </li></ul></ul><ul><ul><li>Controlador </li></ul></ul><ul><ul><li>$c->flash->{error} = “Pagina invalida” </li></ul></ul><ul><ul><li>Plantilla (TT) </li></ul></ul><ul><ul><li>[% error %] </li></ul></ul>
  36. 36. Autenticación / Autorización
  37. 37. Autenticación y autorización --- name: sistap default_view: TT authentication: 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 relación asociada a la tabla de usuarios_roles role_rel: map_user_role # nombre del campo en la tabla de relación usuarios_roles que referencia al usuario (id) user_role_user_field: usuario_id
  38. 38. Autenticación y autorización <ul><li>Configuracion: lib/sistap.pm </li></ul><ul><li>__PACKAGE__->config( name => 'sistap', </li></ul><ul><ul><li>session => { </li></ul></ul><ul><li> expires => 2400, </li></ul><ul><li>storage => '/tmp/session', </li></ul><ul><li>}, </li></ul><ul><li>); </li></ul><ul><li>Acciones </li></ul><ul><ul><li>$c->login($username, $password) ; </li></ul></ul><ul><ul><li>$c->user_exists ; </li></ul></ul><ul><ul><li>$c->user->ciUsuario ; </li></ul></ul><ul><ul><li>$c->check_user_roles('admin') ; </li></ul></ul><ul><ul><li>$c->logout ; </li></ul></ul>
  39. 39. jQuery
  40. 40. ¿Qué es jQuery? <ul><li>Framework de JavaScript </li></ul><ul><li>Selectores de CSS3. </li></ul><ul><li>Manipulación de eventos. </li></ul><ul><li>Ajax. </li></ul><ul><li>Gran cantidad de plugins. </li></ul><ul><ul><li>Tabs. </li></ul></ul><ul><ul><li>Menues. </li></ul></ul><ul><ul><li>Formularios. </li></ul></ul><ul><ul><li>Dialogos. </li></ul></ul><ul><ul><li>Drag and Drop. </li></ul></ul><ul><ul><li>etc ( http://jquery.com/plugins/ ) </li></ul></ul>
  41. 41. jQuery <ul><ul><li>< script type = &quot;text/javascript&quot; src = &quot;[% c.uri_for('/js/jquery-latest.pack-1_2_1.js') %]&quot; > </ script > </li></ul></ul><ul><ul><li>< script type = &quot;text/javascript&quot; > jQuery.noConflict () ; </ script > </li></ul></ul><ul><ul><li>< script type = &quot;text/javascript&quot; > </li></ul></ul><ul><ul><ul><li>jQuery (function(){ </li></ul></ul></ul><ul><ul><ul><ul><li>// El código a ejecutarse cuando se cargue todo el documento acá </li></ul></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>// acá también puede haber código, pero no si se disparará aún cuando </li></ul></ul></ul><ul><ul><ul><li>// el documento no esté cargado </li></ul></ul></ul><ul><ul><li></ script > </li></ul></ul>
  42. 42. jQuery: Selectores <ul><li>Básicamente jQuery(“ selector CSS o xpath ”) </li></ul><ul><li>jQuery ( &quot;#txt_pais&quot; ). val ( jQuery ( &quot;#modal_pais :selected&quot; ). text ()) </li></ul><ul><ul><li>Antes: document.getElementById(“txt_pais”).value = document.getElementById(&quot;modal_pais&quot;).options[document.getElementById(&quot;modal_pais&quot;).selectedIndex].text </li></ul></ul><ul><li>jQuery(&quot;.jd_menu li ul li ul&quot;).parent().addClass(&quot;flecha_menu&quot;); </li></ul><ul><ul><li>Antes: Posiblemente usaría un id por cada elemento y sabiendo quién merece la imagen, se la asigno, sino, del lado del servidor. </li></ul></ul><ul><li>jQuery(&quot;table.cebra tr:even&quot;).addClass(&quot;resaltado&quot;); </li></ul><ul><ul><li>Antes: Si se construye la tabla de forma dinámica (php, perl, python, etc), controlar el número del registro y asignar la clase correspondiente. </li></ul></ul><ul><li>jQuery(&quot;input[@type=text]:visible&quot;).eq(0).focus() </li></ul><ul><ul><li>Antes: Seguro haría lo mismo pero a pie, pasar por todo el fomulario buscando los elementos visibles y luego situarme en el primer elemento. </li></ul></ul>
  43. 43. Ajax (ahah)
  44. 44. Ajax (ahah) <ul><li>Crear vista de JSON. </li></ul><ul><ul><li>perl script/sistap_create view JSON JSON </li></ul></ul><ul><li>La información a enviar como respuesta está en el stash. </li></ul><ul><ul><li>$c->stash->{salida} = “hey”; </li></ul></ul><ul><li>jQuery captura los datos. </li></ul><ul><li>jQuery.getJSON( url , param , function(jsonData){ </li></ul><ul><ul><li>if (jsonData.salida == “hey” ){ </li></ul></ul><ul><ul><ul><li>alert(“fino”); </li></ul></ul></ul><ul><ul><li>}else{ </li></ul></ul><ul><ul><ul><li>alert(“error al obtener la data”); </li></ul></ul></ul><ul><ul><li>} </li></ul></ul><ul><li>}) </li></ul>
  45. 45. Ajax (JSON) <ul><ul><li>jQuery.getJSON( url , parametros , function(jsonData){ // trabajamos con el resultado... jsonData }); </li></ul></ul>my $id_pais = $c->req->param ( “pais_id” ); my @estados = $c->model ( &quot;sistapDB::paises&quot; )->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 '); <ul><ul><li>var param = new Object (); </li></ul></ul><ul><ul><li>param = { pais_id : 3 } ; </li></ul></ul><ul><ul><li>jQuery.getJSON( [% c.uri_for('controlador/accion/') %] , param , function(jsonData){ </li></ul></ul><ul><ul><ul><li>if (jsonData.estados){ </li></ul></ul></ul><ul><ul><ul><li>for (i= 0 ; jsonData.estados.lenght ; i++){ </li></ul></ul></ul><ul><ul><ul><li>// tengo jsonData.estados[i].id_estado y jsonData.estados[i].nombre_estado </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>}else{ </li></ul></ul></ul><ul><ul><ul><ul><li>console.info(“hubo un error al traer la data”); </li></ul></ul></ul></ul><ul><ul><ul><ul><li>// incluso se puede capturar si se acabó el tiempo de sesión </li></ul></ul></ul></ul><ul><ul><ul><ul><li>// de usuario según respuesta y se recarga la página. </li></ul></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>}) </li></ul></ul>
  46. 46. jQuery: plugins <ul><li>Tabs </li></ul><ul><ul><li>http://stilbuero.de/jquery/tabs/ </li></ul></ul><ul><li>menu </li></ul><ul><ul><li>http://jdsharp.us/jQuery/plugins/jdMenu/ </li></ul></ul><ul><li>Thickbox </li></ul><ul><ul><li>http://jquery.com/demo/thickbox/ </li></ul></ul><ul><li>Form </li></ul><ul><ul><li>http://www.malsup.com/jquery/form/ </li></ul></ul><ul><li>Interfaces (interfaces es para para jQuery, lo que script.aculo.us es para prototype) </li></ul><ul><ul><li>http://interface.eyecon.ro/ </li></ul></ul><ul><li>Muchos mas. </li></ul><ul><ul><li>http://jquery.com/plugins/ </li></ul></ul>
  47. 47. jQuery: plugin TABS jQuery(function(){ jQuery('#menu-subvencion').tabs({ fxFade : true , fxSpeed : 'fast' , remote: true }); }) <script type=&quot;text/javascript&quot; src=&quot;[% Catalyst.uri_for('/js/tabs/jquery.history_remote.pack.js') %]&quot;> </script> <script type=&quot;text/javascript&quot; src=&quot;[% Catalyst.uri_for('/js/tabs/jquery.tabs.js') %]&quot;> </script> <link href=&quot;[% Catalyst.uri_for('/js/tabs/jquery.tabs.css') %]&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /> <ul><ul><li><div id=&quot;menu-subvencion&quot; > </li></ul></ul><ul><ul><li><ul > </li></ul></ul><ul><ul><li><li><a href=&quot;[% Catalyst.uri_for('/subvencion/datos_generales') %]&quot;><span>Datos </li></ul></ul><ul><ul><li>generales</span></a></li> </li></ul></ul><ul><ul><li><li><a href=&quot;[% Catalyst.uri_for('/subvencion/resumen') %]&quot; ><span>Resumen</span></a></li> </li></ul></ul><ul><ul><li></ul> </li></ul></ul><ul><ul><li><div> </li></ul></ul>
  48. 48. jQuery: plugin jdMenu <ul><ul><li>$(function(){ </li></ul></ul><ul><ul><li>$('ul.jd_menu').jdMenu(); </li></ul></ul><ul><ul><li>}); </li></ul></ul><script type=&quot;text/javascript&quot; src=&quot;[% Catalyst.uri_for('/js/tabs/jquery.dimmension.js') %]&quot;> </script> <script type=&quot;text/javascript&quot; src=&quot;[% Catalyst.uri_for('/js/tabs/jquery.jdMenu.js') %]&quot;> </script> <link href=&quot;[% Catalyst.uri_for('/js/tabs/jdMenu.css') %]&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /> <link href=&quot;[% Catalyst.uri_for('/js/tabs/jdMenu.slate.css') %]&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /> <ul><ul><li><ul class=&quot;jd_menu jd_menu_slate&quot;> </li></ul></ul><ul><ul><li><li> <a class=&quot;accessible&quot;>Item A</a> </li></ul></ul><ul><ul><li><ul> </li></ul></ul><ul><ul><li><li><a href=&quot;http://www.google.com&quot;>Item 1</a></li> </li></ul></ul><ul><ul><li><li><a href=&quot;http://www.google.com&quot;>Item 2</a></li> </li></ul></ul><ul><ul><li></ul> </li></ul></ul><ul><ul><li></li> </li></ul></ul><ul><ul><li><li> <a class=&quot;accessible&quot;>Item B</a> </li> </li></ul></ul><ul><ul><li></ul> </li></ul></ul>
  49. 49. jQuery: plugin thickbox <script type=&quot;text/javascript&quot; src=&quot;[% Catalyst.uri_for('/js/thickbox/thickbox.js') %]&quot; > </script> <link href=&quot;[% Catalyst.uri_for('/js/thickbox/thickbox.css') %]&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /> <ul><ul><li><input type=&quot;button&quot; class=&quot;thickbox&quot; alt=&quot;#TB_inline?height=150&width=700&inlineId=div_modal_institucion&quot;> </li></ul></ul><ul><ul><li><div id=&quot;div_modal_institucion&quot; style=&quot;display : none&quot; > </li></ul></ul><ul><ul><li><div> </li></ul></ul><ul><ul><li><label> Usuario : </label> <input name=”usuario” id=”usuario” /> </li></ul></ul><ul><ul><li><label> Clave : </label> <input name=”clave” id=”clave” /> </li></ul></ul><ul><ul><li><input type=”button” value=”Login” id=”login” /> </li></ul></ul><ul><ul><li><input type=”button” value=”Cancel” id=”cancel” /> </li></ul></ul><ul><ul><li></div> </li></ul></ul><ul><ul><li></div> </li></ul></ul>
  50. 50. Depuración
  51. 51. Depuración <ul><li>javascript (firebug) : console.info() </li></ul>
  52. 52. Depuración <ul><li>Catalyst : $c->log->debug() </li></ul>
  53. 53. Depuración <ul><li>DBIC: export DBIC_TRACE=”1=/tmp/salida.txt” </li></ul>
  54. 54. Consejos <ul><li>Usar uri_for (en las plantillas y controlador). </li></ul><ul><ul><li><a href=”[% c.uri_for('/controlador/accion/param') %]”>Enlace</a> </li></ul></ul><ul><ul><li>$c->res->redirect( $c->uri_for('/a/b/c') ); </li></ul></ul><ul><li>Usar relaciones en ORM (DBIC). </li></ul><ul><li>Usar Template Toolkit para generar maestros. </li></ul><ul><li>Usar Flash + redirect para mensajes a usuario. </li></ul><ul><li>Usar Ajax solo cuando sea justificado. (No AJfiXiar el sitio) </li></ul><ul><li>Usar Unicode </li></ul><ul><ul><li>BD (UTF-8) </li></ul></ul><ul><ul><li>Servidor web (apache: AddDefaultCharset utf8) </li></ul></ul><ul><ul><li>Archivo (Usar un editor que lo soporte, como vim ) </li></ul></ul><ul><ul><li>Documento ( html: <meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /> ) </li></ul></ul><ul><li>Usar la función “jQuery” en vez de la función anónima ($) </li></ul><ul><ul><li>jQuery.noConflict() </li></ul></ul>
  55. 55. Proyectos libres nacionales desarrollados usando Catalyst ( Que conozco hasta ahora ) <ul><li>Debian::Package::HTML </li></ul><ul><ul><li>http://search.cpan.org/~bureado/Debian-Package-HTML-0.1/lib/Debian/Package/HTML.pm </li></ul></ul><ul><li>PUBuilder </li></ul><ul><ul><li>http://blog.bureado.com.ve/?p=307 </li></ul></ul><ul><li>Sist ap: </li></ul><ul><ul><li>http://sistemas.fsl.fundacite-merida.gob.ve/projects/sistap </li></ul></ul><ul><li>TEGZ: </li></ul><ul><ul><li>http://sistemas.fsl.fundacite-merida.gob.ve/projects/tegz </li></ul></ul>
  56. 56. ¿Preguntas?
  57. 57. Gracias por su atención

×