Catalyst

Catalyst

Overview

Stuff you'll need to know

MVC

Dispatching: The Timeline

  1. foo.plx + if statement - http://foo.com/cgi/foo.plx?mode=add_user
  2. CGI::Application + add_user subroutine - http://foo.com/cgi/foo.plx?mode=add_user
  3. CGI::Application + CGI::Application::Dispatcher - http://foo.com/dispatcher/foo/add_user
  4. Vanilla Catalyst + MyApp::Controller::Foo::add_user - http://foo.com/foo/add_user
  5. Advanced Catalyst - DELETE http://foo.com/users/1/friends/2

Dispatching: Basic Catalyst

Dispatching: Chaining

Dispatching: Chaining Multi Controller

  • package MyApp::Controller::Users;
    # ...
    sub load_users : Chained('/') PathPart('users') CaptureArgs(0) { ... }
    sub users : Chained('load_users') PathPart('') Args(0) { ... }
    sub load_user : Chained('load_users') PathPart('') CaptureArgs(1) { ... }
    sub user : Chained('load_user') PathPart('') Args(0) { ... }
          
  • package MyApp::Controller::Users::Roles;
    # ...
    sub load_roles : Chained('/users/load_users') PathPart('roles') CaptureArgs(0) { ... }
    sub roles : Chained('load_roles') PathPart('') Args(0) { ... }
          
  • NOTE: The second class could have just as easily been named MyApp::Controller::Roles
  • Sidenote: you don't have to use attributes:

    __PACKAGE__->config(
       actions => {
          load_users => { Chained => '/',          PathPart => 'users', CaptureArgs => 0 },
          load_user  => { Chained => 'load_users', PathPart => 'user',  CaptureArgs => 1 },
          load_roles => { Chained => 'load_user',  PathPart => 'roles', CaptureArgs => 0 },
          users      => { Chained => 'load_users', PathPart => '',             Args => 0 },
          user       => { Chained => 'load_user',  PathPart => '',             Args => 0 },
          roles      => { Chained => 'load_roles', PathPart => '',             Args => 0 },
       },
    );
    
    sub load_users { ... }
    sub users { ... }
    sub load_user { ... }
    sub user { ... }
    sub load_roles { ... }
    sub roles { ... }
    

    Why not use attributes?

    Dispatching: Catalyst::Action::REST

    Aside: Why REST?

    Dispatching: Catalyst::Action::REST + Chaining

    Namespaced Stash

    Real Example

    package Lynx::SMS::Controller::Accounts;
    
    use Moose;
    use namespace::autoclean;
    
    use syntax 'method';
    
    BEGIN { extends 'Lynx::SMS::RESTController' };
    
    with 'Catalyst::TraitFor::Controller::DBIC::DoesPaging',
         'Catalyst::TraitFor::Controller::DoesExtPaging';
    
    sub base : Chained('/') PathPart('accounts') CaptureArgs(0) {
       my ($self, $c) = @_;
       $c->stash->{+__PACKAGE__}{rs} = $c->model('DB::Account');
    }
    
    sub item : Chained('base') PathPart('') CaptureArgs(1) {
       my ($self, $c, $id) = @_;
       $c->stash->{+__PACKAGE__}{id} = $id;
       $c->stash->{+__PACKAGE__}{thing} =
          $c->stash->{+__PACKAGE__}{rs}->find($id);
    }
    
    sub accounts :Chained('base') PathPart('') Args(0) ActionClass('REST') {}
    
    method accounts_POST($c) : RequiresRole('write') {
       my $params = $c->request->data->{data};
    
       my $foo = $c->stash->{+__PACKAGE__}{rs}->create($params);
    
       $c->stash->{rest} = { success => 1, data => $foo };
    }
    
    method accounts_GET($c) : RequiresRole('read') {
       $c->stash->{rest} = $self->ext_paginate(
          $self->search($c,
             $self->paginate($c,
                $self->sort($c, $c->stash->{+__PACKAGE__}{rs})
             )
          )
       );
    }
    
    sub account :Chained('item') PathPart('') Args(0) ActionClass('REST') {}
    
    method account_GET($c) : RequiresRole('read') {
       $c->stash->{rest} = {
          success => 1,
          data => $c->stash->{+__PACKAGE__}{thing},
       };
    }
    
    method account_PUT($c) : RequiresRole('write') {
       my $foo = $c->stash->{+__PACKAGE__}{thing};
       my $params = $c->request->data->{data};
       $foo->update($params);
    
       $c->stash->{rest} = { success => 1, data => $foo };
    }
    
    method account_DELETE($c) : RequiresRole('delete') {
       $c->stash->{+__PACKAGE__}{rs}->search({
          id => $c->stash->{+__PACKAGE__}{id},
       })->delete;
       $c->stash->{rest} = { success => 1 };
    }

    Rich Ecosystem

    1. All that sticky glue
    2. too much to talk about
    3. what should you use

    Configuration

    MyApp::Util

    My Stuff

    Logging

    Testing

    TXN Wrap

    Catalyst::TraitFor::Request::REST::ForBroswers

    MTSI::Controller::REST

    CatalystX::InjectComponent

    Catalyst::Controller::Accessors

    Questions?

    Meta

    /

    #