Perl web frameworks   Catalyst & Mojolicious     Curs avançat de Perl 2012            10/03/2012
Perl web frameworks          Hola!      Diego Kuperman      diegok | @freekey
Web frameworks       ~     MVC
Router    ~Dispatcher
Rutas//prueba-curso/event/23/event/23/where/event/23-una-prueba/picture/3/event/23/picture/3/event/una-prueba/pic/3
Rutas//prueba-curso/event/23/event/23/where/event/23-una-prueba/picture/3/event/23/picture/3/event/una-prueba/pic/3
Controller
Invocado por el dispatcherManipulación de capturas del routerValidacionesPegamento entre otros componentes:modelos y vista...
Model   ~Storage
ModelHabitualmente base de datosLógica de negocioUso fuera de la appTests independientes de la appOtros modelos: git, api-...
View          ~Templates / Serializers
ViewNormalmente un motor de templatesMUCHAS opciones en CPANTemplate toolkit en CatalystEP en MojoliciousSerialización: JS...
Install  ~CPAN
Catalyst$   cpanm   -n   Catalyst::Runtime Catalyst::Devel$   cpanm   -n   Catalyst::View::TT Catalyst::View::JSON$   cpan...
Mojolicious                   http://mojolicio.us                   The web in a box$ cpanm -n Mojolicious
Catalyst vs Mojolicious
Catalyst
$ git clone git://github.com/diegok/dbic.curs.barcelona.pm.git$ cd dbic.curs.barcelona.pm$ dzil build; cpanm -n *.tar.gz; ...
CatalystThe elegant MVC framework
Catalyst                   Crear nueva App$ catalyst.pl MyCatAppcreated "MyCatApp"created "MyCatApp/script"created "MyCatA...
├──   Changes├──   Makefile.PL├──   README├──   lib│     └── Curs|         ├── App│         │   ├── Controller│         │ ...
├──   root│     ├── favicon.ico│     └── static│         └── images│             ├── ...│             └── catalyst_logo.pn...
package Curs::App;use Moose;use namespace::autoclean;use Catalyst::Runtime 5.80;use Catalyst qw/    -Debug    ConfigLoader...
package Curs::App;use Moose;use namespace::autoclean;use Catalyst::Runtime 5.80;use Catalyst qw/    ConfigLoader    Static...
$ ./script/curs_app_server.pl -r -d[debug] Debug messages enabled[debug] Statistics enabled[debug] Loaded plugins:.-------...
$ ./script/curs_app_server.pl -r -d[debug] Loaded Path actions:.--------------------------------+-----------------------.|...
package Curs::App::Controller::Root;use Moose; use namespace::autoclean;BEGIN { extends Catalyst::Controller }__PACKAGE__-...
TieneRouter + DispatcherStatic::SimpleController RootAcción por defecto
aún no tiene...Vista/sModelo/s+ControllersNinguna gracia!
Contexto  ~  $c
Catalyst::Request$c->request$c->req # alias$c->req->params->{foo};$c->req->cookies->{name};$c->req->headers->content_type;...
Catalyst::Response$c->response$c->res # alias$c->res->body(Hello World);$c->res->status(404);$c->res->redirect(http://barc...
Catalyst::Log$c->log$c->log->debug(Something happened);$c->log->info(Something you should know);
Stash$c->stash( key => value );$c->stash( key ); # value$c->stash->{key} = [1..10];$c->stash->{key};   # [1..10]     Dura ...
Routes        ~Controller actions
Nuevo Controller$ ./script/curs_app_create.pl controller Example exists ".../Curs-App/script/lib/Curs/App/Controller" exis...
lib/Curs/App/Controller/Example.pmpackage Curs::App::Controller::Example;use Moose; use namespace::autoclean;BEGIN {extend...
Controller ActionsLiteral match (:Path)Root-level (:Global) = Path(/...)Namespace-prefixed (:Local) = Path(.../)Restricció...
/example/cero/...sub cero :Local {    my ( $self, $c, @args ) = @_;    $c->res->body(Args:  . join , , @args);}           ...
/example/dossub dos :Path(dos) :Args(0) {    my ( $self, $c ) = @_;    $c->res->body(":Path(dos) :Args(0)");}           /e...
/hola/mundosub cuatro :Path(/hola) :Args(1) {    my ( $self, $c, $arg1 ) = @_;    $c->res->body("Hola $arg1!");}
Controller Actions     Pattern-match    :Regex() & :LocalRegex()
/item23/order32sub cinco  :Regex(^item(d+)/order(d+)$) {    my ( $self, $c ) = @_;    my $item = $c->req->captures->[0];  ...
/example/item23/order32sub seis  :LocalRegex(^item(d+)/order(d+)$) {    my ( $self, $c ) = @_;    my $item = $c->req->capt...
Controller Actions  Privadas & control flow            :Private      forward() & detach()
sub now :Local :Args(0) {    my ( $self, $c ) = @_;    $c->forward(stash_now);    $c->detach(say_now);    $c->log->debug(o...
Built-in special actions
Default controller actionsub default : Path {}     Como default, con mas precedenciasub index :Path Args(0) {}
Antes de la acción, solo una vezsub begin :Private {}     Despues de la acción, solo una vezsub end :Private {}Despues de ...
Chained actions    :Chained
sub with_now : PathPart(example/now)    Chained( / ) CaptureArgs( 0 ) {    my ( $self, $c ) = @_;    $c->forward(stash_now...
Chained es MUY potente, pero antes tenemos queañadir algunas cosas mas...
VistasTemplate toolkit      +   JSON
$ script/curs_app_create.pl view Web TTexists ".../Curs-App/script/../lib/Curs/App/View"exists ".../Curs-App/script/../t"c...
lib/Curs/App/View/Web.pmCurs::App::View::Web;use Moose;extends Catalyst::View::TT;__PACKAGE__->config(    TEMPLATE_EXTENSI...
lib/Curs/App.pm__PACKAGE__->config( # ... View::Web => {  INCLUDE_PATH => [    __PACKAGE__->path_to(root, src),    __PACKA...
root/lib/layout<!DOCTYPE HTML><html lang="en-us">  <head>  <meta http-equiv="Content-type" content="text/  <title>Curs ava...
TT y layout en su sitio,hora de cambiar la home
root/src/index.tt<h1>[% message %]</h1>       lib/Curs/App/Controller/Root.pmsub index :Path :Args(0) {    my ( $self, $c ...
$ ./script/curs_app_create.pl view JSON JSON exists "lib/Curs/App/View" exists "t/"created "lib/Curs/App/View/JSON.pm"crea...
lib/Curs/App.pm__PACKAGE__->config({    ...    View::JSON => {        expose_stash => json, # defaults to ev    },    defa...
Uso de View::JSONsub status :Path(/status) :Args(0) {    my ( $self, $c ) = @_;    $c->stash(        json => { value => te...
Modelo DBIC
Curs::Schema$ script/curs_app_create.pl model DB DBIC::Schema Curs::Schemaexists ".../Curs-App/script/../lib/Curs/App/Mode...
Config por defecto                 curs_app.confname Curs::App<Model::DB>    connect_info   dbi:SQLite:dbname=curs_schema ...
Deploy!$ ./script/schema_deploy.plCreating sql/Curs-Schema-1-SQLite.sql => done.Making initial deploy (ddbb has no version...
Nuestro schema es un    componente más ahora!sub action :Local {  my ( $self, $c ) = @_;    $c->res->body(      $c->model(...
Authentication     &Authorization
Catalyst::Plugin::Authentication                       &   Catalyst::Plugin:Authorization::Roles            + Catalyst::Pl...
lib/Curs/App.pmuse Catalyst qw/    ...     Session     Session::State::Cookie     Session::Store::File     Authentication ...
__PACKAGE__->config(    ...    Plugin::Authentication => {      default_realm => users,      realms        => {        use...
}       }     },);Nuevos metodos en la app$c->authenticate(    email    => $email,    password => $pwd);$c->user_exists;$c...
Todo listoNecesitamos un form para login             :-(
HTML::FormHandler  al rescate! :-)
lib/Curs/App/Form/Login.pmpackage Curs::App::Form::Login;use HTML::FormHandler::Moose;extends HTML::FormHandler;use Email:...
lib/Curs/App/Form/Login.pmhas_field password => (    type => Password,    required => 1);has_field submit   => (    type =...
Ahora sí!
Un controller nuevo para             auth$ ./script/curs_app_create.pl controller Auth...
lib/Curs/App/Controller/Auth.pmpackage Curs::App::Controller::Auth;use Moose; use namespace::autoclean;BEGIN {extends Cata...
sub login :Path(/login) Args(0) {  my ( $self, $c ) = @_;  my $form = Curs::App::Form::Login->new();  my $creds = {    ema...
root/src/auth/login.tt<div id="login">  [% form.render %]</div>
=head2 need_login Ensure user exists on the chain.=cutsub need_login :PathPart(  )    Chained( / ) CaptureArgs( 0 ) {  my ...
=head2 need_role_admin Ensure user with the admin role.=cutsub need_role_admin :PathPart(admin)    Chained(need_login) Cap...
En otro controller... perdido en otra galaxia ...
=head2 element_chainBase chain for actions related to one user=cutsub element_chain    :PathPart(user)     Chained(/auth/n...
sub view :PathPart()    Chained(element_chain) Args(0) {  my ( $self, $c ) = @_;  $c->stash( template => user/view.tt );}s...
Plugin   vsTraitFor
Plugin global        vsPlugin for component
TraitFor Controller  Role para el controller
package Catalyst::TraitFor::Controller::WithDateuse MooseX::MethodAttributes::Role;use namespace::autoclean;use DateTime;h...
Traits locales
package Curs::App::TraitFor::Controller::WithDBIuse MooseX::MethodAttributes::Role;use namespace::autoclean;require model_...
...sub item :PathPart() Chained(base_chain) Cap    my ( $self, $c, $id ) = @_;    $c->stash->{ $self->stash_key }        =...
A consumir!
package Curs::App::Controller::Event;use Moose; use namespace::autoclean;BEGIN {extends Catalyst::Controller}has model_nam...
https://metacpan.org/search?q=catalyst          896 results
Plack(ya lo estamos usando)
$ cpanm -n Starman...$ starman curs_app.psgi2012/03/10-11:25:36 Starman::Server(type Net::Server::PreFork) starting! pid(7...
Más Catalyst                  IRC#catalyst en irc.perl.org.#catalyst-dev en irc.perl.org (desarrollo).              Mailin...
Manual           Ejercicioshttps://metacpan.org/module/Catalyst::ManualAñadir un metodo (API) que deje verdatos de UN usua...
Curscatalyst
Curscatalyst
Curscatalyst
Upcoming SlideShare
Loading in...5
×

Curscatalyst

1,154

Published on

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
1,154
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
5
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Curscatalyst

  1. 1. Perl web frameworks Catalyst & Mojolicious Curs avançat de Perl 2012 10/03/2012
  2. 2. Perl web frameworks Hola! Diego Kuperman diegok | @freekey
  3. 3. Web frameworks ~ MVC
  4. 4. Router ~Dispatcher
  5. 5. Rutas//prueba-curso/event/23/event/23/where/event/23-una-prueba/picture/3/event/23/picture/3/event/una-prueba/pic/3
  6. 6. Rutas//prueba-curso/event/23/event/23/where/event/23-una-prueba/picture/3/event/23/picture/3/event/una-prueba/pic/3
  7. 7. Controller
  8. 8. Invocado por el dispatcherManipulación de capturas del routerValidacionesPegamento entre otros componentes:modelos y vistasIdealmente poco código: thin controller,fat models.
  9. 9. Model ~Storage
  10. 10. ModelHabitualmente base de datosLógica de negocioUso fuera de la appTests independientes de la appOtros modelos: git, api-rest, ...
  11. 11. View ~Templates / Serializers
  12. 12. ViewNormalmente un motor de templatesMUCHAS opciones en CPANTemplate toolkit en CatalystEP en MojoliciousSerialización: JSON, XML, YAML, ...
  13. 13. Install ~CPAN
  14. 14. Catalyst$ cpanm -n Catalyst::Runtime Catalyst::Devel$ cpanm -n Catalyst::View::TT Catalyst::View::JSON$ cpanm -n Catalyst::Plugin::Unicode::Encoding$ cpanm -n Catalyst::Plugin::Session$ cpanm -n Catalyst::Plugin::Session::Store::File$ cpanm -n Catalyst::Plugin::Session::State::Cookie$ cpanm -n Catalyst::Plugin::Authentication$ cpanm -n Catalyst::Plugin::Authorization::Roles$ cpanm -n Catalyst::Authentication::Store::DBIx::Class$ cpanm -n HTML::FormHandler HTML::FormHandler::Model::DBIC
  15. 15. Mojolicious http://mojolicio.us The web in a box$ cpanm -n Mojolicious
  16. 16. Catalyst vs Mojolicious
  17. 17. Catalyst
  18. 18. $ git clone git://github.com/diegok/dbic.curs.barcelona.pm.git$ cd dbic.curs.barcelona.pm$ dzil build; cpanm -n *.tar.gz; dzil clean$ git clone git://github.com/diegok/app.curs.barcelona.pm.git$ cd app.curs.barcelona.pm$ cpanm -n --installdeps .
  19. 19. CatalystThe elegant MVC framework
  20. 20. Catalyst Crear nueva App$ catalyst.pl MyCatAppcreated "MyCatApp"created "MyCatApp/script"created "MyCatApp/lib"created "MyCatApp/root"created "MyCatApp/root/static"...created "MyCatApp/script/mycatapp_server.pl"created "MyCatApp/script/mycatapp_test.pl"created "MyCatApp/script/mycatapp_create.pl"
  21. 21. ├── Changes├── Makefile.PL├── README├── lib│ └── Curs| ├── App│ │ ├── Controller│ │ │ └── Root.pm│ │ ├── Model│ | └── View│ └── App.pm├── curs_app.conf├── curs_app.psgi
  22. 22. ├── root│ ├── favicon.ico│ └── static│ └── images│ ├── ...│ └── catalyst_logo.png├── script│ ├── ...│ ├── curs_app_create.pl│ └── curs_app_server.pl└── t ├── 01app.t ├── 02pod.t └── 03podcoverage.t
  23. 23. package Curs::App;use Moose;use namespace::autoclean;use Catalyst::Runtime 5.80;use Catalyst qw/ -Debug ConfigLoader Static::Simple/;extends Catalyst;our $VERSION = 0.01;__PACKAGE__->config( name => Curs::App, disable_component_resolution_regex_fallback enable_catalyst_header => 1, # Send X-Cataly);__PACKAGE__->setup();
  24. 24. package Curs::App;use Moose;use namespace::autoclean;use Catalyst::Runtime 5.80;use Catalyst qw/ ConfigLoader Static::Simple/;extends Catalyst;our $VERSION = 0.01;__PACKAGE__->config( name => Curs::App, disable_component_resolution_regex_fallback enable_catalyst_header => 1, # Send X-Cataly);__PACKAGE__->setup();
  25. 25. $ ./script/curs_app_server.pl -r -d[debug] Debug messages enabled[debug] Statistics enabled[debug] Loaded plugins:.-------------------------------------------------------.| Catalyst::Plugin::ConfigLoader 0.30 |-------------------------------------------------------[debug] Loaded dispatcher "Catalyst::Dispatcher"[debug] Loaded engine "Catalyst::Engine"[debug] Found home "/.../Curs-App"[debug] Loaded Config "/.../Curs-App/curs_app.conf"[debug] Loaded components:.--------------------------------------------+----------.| Class | Type |+--------------------------------------------+----------+| Curs::App::Controller::Root | instance |--------------------------------------------+----------[debug] Loaded Private actions:.-------------+-----------------------------+------------.| Private | Class | Method |+-------------+-----------------------------+------------+| /default | Curs::App::Controller::Root | default || /end | Curs::App::Controller::Root | end || /index | Curs::App::Controller::Root | index |-------------+-----------------------------+------------
  26. 26. $ ./script/curs_app_server.pl -r -d[debug] Loaded Path actions:.--------------------------------+-----------------------.| Path | Private |+--------------------------------+-----------------------+| / | /index || /... | /default |--------------------------------+-----------------------[info] Curs::App powered by Catalyst 5.90010HTTP::Server::PSGI: Accepting connections at http://0:3000/
  27. 27. package Curs::App::Controller::Root;use Moose; use namespace::autoclean;BEGIN { extends Catalyst::Controller }__PACKAGE__->config(namespace => );sub index :Path :Args(0) { my ( $self, $c ) = @_; $c->response->body($c->welcome_message);}sub default :Path { my ( $self, $c ) = @_; $c->response->body(Page not found); $c->response->status(404);}sub end : ActionClass(RenderView) {}
  28. 28. TieneRouter + DispatcherStatic::SimpleController RootAcción por defecto
  29. 29. aún no tiene...Vista/sModelo/s+ControllersNinguna gracia!
  30. 30. Contexto ~ $c
  31. 31. Catalyst::Request$c->request$c->req # alias$c->req->params->{foo};$c->req->cookies->{name};$c->req->headers->content_type;$c->req->base;$c->req->uri_with( { page => 3 } );
  32. 32. Catalyst::Response$c->response$c->res # alias$c->res->body(Hello World);$c->res->status(404);$c->res->redirect(http://barcelona.pm);# CGI::Simple::Cookie$c->res->cookies->{foo} = { value => 123 };
  33. 33. Catalyst::Log$c->log$c->log->debug(Something happened);$c->log->info(Something you should know);
  34. 34. Stash$c->stash( key => value );$c->stash( key ); # value$c->stash->{key} = [1..10];$c->stash->{key}; # [1..10] Dura un request-response completo Paso de datos entre componentes
  35. 35. Routes ~Controller actions
  36. 36. Nuevo Controller$ ./script/curs_app_create.pl controller Example exists ".../Curs-App/script/lib/Curs/App/Controller" exists ".../Curs-App/script/t"created ".../Curs-App/lib/Curs/App/Controller/Example.pm"created ".../Curs-App/t/controller_Example.t"
  37. 37. lib/Curs/App/Controller/Example.pmpackage Curs::App::Controller::Example;use Moose; use namespace::autoclean;BEGIN {extends Catalyst::Controller; }# /examplesub index :Path :Args(0) { my ( $self, $c ) = @_; $c->res->body(Example index match!);}
  38. 38. Controller ActionsLiteral match (:Path)Root-level (:Global) = Path(/...)Namespace-prefixed (:Local) = Path(.../)Restricción de argumentos (:Args)
  39. 39. /example/cero/...sub cero :Local { my ( $self, $c, @args ) = @_; $c->res->body(Args: . join , , @args);} /example/unosub uno :Local :Args(0) { my ( $self, $c ) = @_; $c->res->body(:Local :Args(0));}
  40. 40. /example/dossub dos :Path(dos) :Args(0) { my ( $self, $c ) = @_; $c->res->body(":Path(dos) :Args(0)");} /example/tressub tres :Path(/example/tres) :Args(0) { my ( $self, $c ) = @_; $c->res->body(":Path(/example/tres) :Args(}
  41. 41. /hola/mundosub cuatro :Path(/hola) :Args(1) { my ( $self, $c, $arg1 ) = @_; $c->res->body("Hola $arg1!");}
  42. 42. Controller Actions Pattern-match :Regex() & :LocalRegex()
  43. 43. /item23/order32sub cinco :Regex(^item(d+)/order(d+)$) { my ( $self, $c ) = @_; my $item = $c->req->captures->[0]; my $order = $c->req->captures->[1]; $c->res->body( "(cinco) Item: $item | Order: $order" );}
  44. 44. /example/item23/order32sub seis :LocalRegex(^item(d+)/order(d+)$) { my ( $self, $c ) = @_; my $item = $c->req->captures->[0]; my $order = $c->req->captures->[1]; $c->res->body( "(seis) Item: $item | Order: $order" );}
  45. 45. Controller Actions Privadas & control flow :Private forward() & detach()
  46. 46. sub now :Local :Args(0) { my ( $self, $c ) = @_; $c->forward(stash_now); $c->detach(say_now); $c->log->debug(ouch!);}sub stash_now :Private { my ( $self, $c ) = @_; $c->stash( now => DateTime->now );}sub say_now :Private { my ( $self, $c ) = @_; $c->res->body($c->stash->{now});}
  47. 47. Built-in special actions
  48. 48. Default controller actionsub default : Path {} Como default, con mas precedenciasub index :Path Args(0) {}
  49. 49. Antes de la acción, solo una vezsub begin :Private {} Despues de la acción, solo una vezsub end :Private {}Despues de begin, de menos especifico a mas especificosub auto :Private {} Si retorna false se salta hasta end()
  50. 50. Chained actions :Chained
  51. 51. sub with_now : PathPart(example/now) Chained( / ) CaptureArgs( 0 ) { my ( $self, $c ) = @_; $c->forward(stash_now);}sub show_now : PathPart(show) Chained( with_now ) Args( 0 ) { my ( $self, $c ) = @_; $c->detach(say_now);}
  52. 52. Chained es MUY potente, pero antes tenemos queañadir algunas cosas mas...
  53. 53. VistasTemplate toolkit + JSON
  54. 54. $ script/curs_app_create.pl view Web TTexists ".../Curs-App/script/../lib/Curs/App/View"exists ".../Curs-App/script/../t"created ".../Curs-App/script/../lib/Curs/App/View/Web.pm"created ".../Curs-App/script/../t/view_Web.t"
  55. 55. lib/Curs/App/View/Web.pmCurs::App::View::Web;use Moose;extends Catalyst::View::TT;__PACKAGE__->config( TEMPLATE_EXTENSION => .tt, CATALYST_VAR => c, TIMER => 0, ENCODING => utf-8 WRAPPER => layout, render_die => 1,);1;
  56. 56. lib/Curs/App.pm__PACKAGE__->config( # ... View::Web => { INCLUDE_PATH => [ __PACKAGE__->path_to(root, src), __PACKAGE__->path_to(root, lib), ], },);
  57. 57. root/lib/layout<!DOCTYPE HTML><html lang="en-us"> <head> <meta http-equiv="Content-type" content="text/ <title>Curs avançat de Perl 2012</title> <link rel="stylesheet" href="/css/style.css" t </head> <body> [% content %] </body></html>
  58. 58. TT y layout en su sitio,hora de cambiar la home
  59. 59. root/src/index.tt<h1>[% message %]</h1> lib/Curs/App/Controller/Root.pmsub index :Path :Args(0) { my ( $self, $c ) = @_; $c->stash( message => Hola mundo!, template => index.tt );}
  60. 60. $ ./script/curs_app_create.pl view JSON JSON exists "lib/Curs/App/View" exists "t/"created "lib/Curs/App/View/JSON.pm"created "t/view_JSON.t"
  61. 61. lib/Curs/App.pm__PACKAGE__->config({ ... View::JSON => { expose_stash => json, # defaults to ev }, default_view => Web,});
  62. 62. Uso de View::JSONsub status :Path(/status) :Args(0) { my ( $self, $c ) = @_; $c->stash( json => { value => testing } ); $c->forward(View::JSON);}
  63. 63. Modelo DBIC
  64. 64. Curs::Schema$ script/curs_app_create.pl model DB DBIC::Schema Curs::Schemaexists ".../Curs-App/script/../lib/Curs/App/Model"exists ".../Curs-App/script/../t"created ".../Curs-App/script/../lib/Curs/App/Model/DB.pm"created ".../Curs-App/script/../t/model_DB.t"
  65. 65. Config por defecto curs_app.confname Curs::App<Model::DB> connect_info dbi:SQLite:dbname=curs_schema connect_info connect_info <connect_info> sqlite_unicode 1 RaiseError 1 </connect_info></Model::DB>
  66. 66. Deploy!$ ./script/schema_deploy.plCreating sql/Curs-Schema-1-SQLite.sql => done.Making initial deploy (ddbb has no version) => done.
  67. 67. Nuestro schema es un componente más ahora!sub action :Local { my ( $self, $c ) = @_; $c->res->body( $c->model(DB::User)->first->email );}
  68. 68. Authentication &Authorization
  69. 69. Catalyst::Plugin::Authentication & Catalyst::Plugin:Authorization::Roles + Catalyst::Plugin::Session
  70. 70. lib/Curs/App.pmuse Catalyst qw/ ... Session Session::State::Cookie Session::Store::File Authentication Authorization::Roles/;
  71. 71. __PACKAGE__->config( ... Plugin::Authentication => { default_realm => users, realms => { users => { credential => { class => Password, password_field => password, password_type => self_check, }, store => { class => DBIx::Class, user_model => DB::User, role_relation => roles, role_field => name, id_field => email } } }
  72. 72. } } },);Nuevos metodos en la app$c->authenticate( email => $email, password => $pwd);$c->user_exists;$c->user;
  73. 73. Todo listoNecesitamos un form para login :-(
  74. 74. HTML::FormHandler al rescate! :-)
  75. 75. lib/Curs/App/Form/Login.pmpackage Curs::App::Form::Login;use HTML::FormHandler::Moose;extends HTML::FormHandler;use Email::Valid;has_field email => ( type => Text, required => 1, apply => [{ check => sub { Email::Valid->address( $_[0] ) }, message => Must be a valid email addres }]);
  76. 76. lib/Curs/App/Form/Login.pmhas_field password => ( type => Password, required => 1);has_field submit => ( type => Submit, value => Login);
  77. 77. Ahora sí!
  78. 78. Un controller nuevo para auth$ ./script/curs_app_create.pl controller Auth...
  79. 79. lib/Curs/App/Controller/Auth.pmpackage Curs::App::Controller::Auth;use Moose; use namespace::autoclean;BEGIN {extends Catalyst::Controller; }use Curs::App::Form::Login;
  80. 80. sub login :Path(/login) Args(0) { my ( $self, $c ) = @_; my $form = Curs::App::Form::Login->new(); my $creds = { email => $form->value->{email}, password => $form->value->{password} }; if ( $form->process( params => $c->req->params if ( $c->authenticate( $creds ) ) { $c->detach(after_login_redirect); } else { $form->field(password)->add_error( Inva } } $c->stash( template => auth/login.tt, form => $form );}
  81. 81. root/src/auth/login.tt<div id="login"> [% form.render %]</div>
  82. 82. =head2 need_login Ensure user exists on the chain.=cutsub need_login :PathPart( ) Chained( / ) CaptureArgs( 0 ) { my ( $self, $c ) = @_; unless ( $c->user_exists ) { $c->session->{after_login_path} = / . $c-> $c->res->redirect( $c->uri_for_action( $c->controller(Auth) ->action_for(login) ) ); $c->detach; }}
  83. 83. =head2 need_role_admin Ensure user with the admin role.=cutsub need_role_admin :PathPart(admin) Chained(need_login) CaptureArgs(0) { my ( $self, $c ) = @_; unless ( $c->check_user_roles( admin ) ) { $c->res->body(You need admin role for this $c->detach(); }}
  84. 84. En otro controller... perdido en otra galaxia ...
  85. 85. =head2 element_chainBase chain for actions related to one user=cutsub element_chain :PathPart(user) Chained(/auth/need_login) CaptureArgs(1) { my ( $self, $c, $user_id ) = @_; $c->stash( user => $c->model(DB::User) ->find( $user_id ) ); unless ( $c->stash->{user} ) { $c->detach( /error/element_not_found, [ u }}
  86. 86. sub view :PathPart() Chained(element_chain) Args(0) { my ( $self, $c ) = @_; $c->stash( template => user/view.tt );}sub delete :PathPart() Chained(element_chain) Args(0) { my ( $self, $c ) = @_; $c->stash->{user}->delete; # ...}
  87. 87. Plugin vsTraitFor
  88. 88. Plugin global vsPlugin for component
  89. 89. TraitFor Controller Role para el controller
  90. 90. package Catalyst::TraitFor::Controller::WithDateuse MooseX::MethodAttributes::Role;use namespace::autoclean;use DateTime;has stash_key => ( is => ro, default => datafter auto => sub { my ( $self, $c ) = @_; $c->stash( $self->stash_key => DateTime->now};sub auto : Private { 1 }
  91. 91. Traits locales
  92. 92. package Curs::App::TraitFor::Controller::WithDBIuse MooseX::MethodAttributes::Role;use namespace::autoclean;require model_name;require base_chain;has stash_key => ( is => ro, default => sub { lc @{[split /::/, shift->model_name ]}[- });
  93. 93. ...sub item :PathPart() Chained(base_chain) Cap my ( $self, $c, $id ) = @_; $c->stash->{ $self->stash_key } = $c->model( $self->model_name )->find($ || $c->detach(missing);}sub missing { my ( $self, $c ) = @_; $c->res->code(404); $c->res->body(Not found!);}1;
  94. 94. A consumir!
  95. 95. package Curs::App::Controller::Event;use Moose; use namespace::autoclean;BEGIN {extends Catalyst::Controller}has model_name => ( is => ro, default => DB::with Curs::App::TraitFor::Controller::WithDBICsub base_chain :PathPart(event) Chained(/) CaptureArgs(1) {}sub delete :PathPart(delete) Chained(item) A my ( $self, $c ) = @_; $c->stash->{event}->delete;}
  96. 96. https://metacpan.org/search?q=catalyst 896 results
  97. 97. Plack(ya lo estamos usando)
  98. 98. $ cpanm -n Starman...$ starman curs_app.psgi2012/03/10-11:25:36 Starman::Server(type Net::Server::PreFork) starting! pid(73661)Binding to TCP port 5000 on host *Setting gid to "20 20 20 204 100 98 81 80 79 61
  99. 99. Más Catalyst IRC#catalyst en irc.perl.org.#catalyst-dev en irc.perl.org (desarrollo). Mailing listshttp://lists.scsys.co.uk/mailman/listinfo/catalysthttp://lists.scsys.co.uk/mailman/listinfo/catalyst-dev
  100. 100. Manual Ejercicioshttps://metacpan.org/module/Catalyst::ManualAñadir un metodo (API) que deje verdatos de UN usuario en JSON:/user/1/json Extra: vista json que devuelva array de usuarios (sin repetir codigo)Añadir una vista que liste los eventos(Creados en la práctica anterior)Crear una acción (solo para admins), unformulario y su plantilla para crear unevento y otra para editarlo.
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×