Arthur Axel "fREW" Schmidt
Autumn Equinox 2011
$c->model('DB') $c->view('TT') $c->request
$c->response
sub add_user : Local { ... } sub home : Global { ... } sub add_friend : Path('add_buddy') { ... } sub about : Path('/about') { ... } 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) { ... } sub load_roles : Chained('load_user') PathPart('roles') CaptureArgs(0) { ... } sub roles : Chained('load_roles') PathPart('') Args(0) { ... }
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) { ... }
__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 { ... }
with 'Lynx::TraitFor::Controller::RunMethod';
__PACKAGE__->config(
go_prefix => 'configure',
actions => {
go => {
Chained => '/currentuser/shareddashboards/gadgets/item',
PathPart => 'configure',
},
},
);
sub users : Local ActionClass('REST') {}
sub users_GET { ... } # GET /foo/users
# GET /foo/users/1
# GET /foo/users/1/2/3/4/5
sub users_POST :Args(0) { ... } # POST /foo/users
sub users_PUT :Args(1) { ... } # PUT /foo/users/1
sub users_DELETE :Args(1) { ... } # DELETE /foo/users/1
sub base : Chained('/') PathPart('users') { ... } sub users : Chained('base') PathPart('') ActionClass('REST') {}
sub users_GET { ... } # GET /users
sub users_POST { ... } # POST /users
sub item : Chained('base') PathPart('') CatpureArgs(1) { ... } sub user : Chained('item') PathPart('')ActionClass('REST') {}
sub user_GET { ... } # GET /users/1
sub user_PUT { ... } # PUT /users/1
sub user_DELETE { ... } # DELETE /users/1
$c->stash->{+__PACKAGE__}{foo}
$c->stash->{'MyApp::Controller::Users'}{foo}
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 };
}
log4perl.rootLogger=ALL, SCREEN, LOGFILE
log4perl.appender.SCREEN=Log::Log4perl::Appender::Screen
log4perl.appender.SCREEN.utf8=1
log4perl.appender.SCREEN.layout=PatternLayout
log4perl.appender.SCREEN.layout.ConversionPattern=<%c> [%p] %m%n
log4perl.appender.LOGFILE=Log::Log4perl::Appender::File
log4perl.appender.LOGFILE.filename=/var/log/myerrs.log
log4perl.appender.LOGFILE.mode=append
log4perl.filter.important = Log::Log4perl::Filter::LevelRange
log4perl.filter.important.LevelMin = WARN
log4perl.filter.important.LevelMax = FATAL
log4perl.filter.important.AcceptOnMatch = true
log4perl.filter.catalyst = sub { my %p = @_; $p{log4p_category} =~ /^catalyst/i }
log4perl.filter.not_important_catalyst = Log::Log4perl::Filter::Boolean
log4perl.filter.not_important_catalyst.logic = !catalyst || important
# MyApp/Util.pm
sub init_logger {
require Log::Log4perl;
require Log::Contextual;
Log::Log4perl->init_and_watch('lynx_sms_logger.conf');
Log::Contextual::set_logger(sub {
Log::Log4perl::get_logger($_[0])
});
}
# script.pl use MyApp::Util; MyApp::Util::init_logger();
# MyApp.pm
unless (__PACKAGE__->debug) {
require Log::Log4perl;
require Try::Tiny;
if (Try::Tiny::try { Log::Log4perl::get_logger() }) {
no strict 'refs';
*log = sub { Log::Log4perl::get_logger(scalar caller) }
}
}
# t/lib/MyApp/Test.pm
sub as_psgi {
my $app;
if (Lynx::Util::mode() eq 'live') {
plan skip_all => 'Set the LIVE_TEST_SERVER envvar to run live tests'
unless $ENV{LIVE_TEST_SERVER};
require Plack::App::Proxy;
$app = Plack::App::Proxy
->new( remote => "http://$ENV{LIVE_TEST_SERVER}" )
->to_app;
} else {
require Lynx;
require Plack::Builder;
require Plack::App::File;
my $builder = Plack::Builder->new;
$builder->mount('/app' => Lynx->psgi_app);
$builder->mount('/' => Plack::App::File->new(root => ".")->to_app);
$app = $builder;
}
return $app
}
my $mech = Test::WWW::Mechanize::PSGI->new( app => $app ); $mech->get( "/cgi/logon.plx?UserID=test&Password=test" ); $mech->content_lacks( 'Login Error', 'Login should succeed'); $mech->content_lacks( 'ODBC Error', 'No DB error');
around dispatch => sub {
my ($orig, $self, @args) = (@_);
return $self->model('DB')->txn_do(sub { $self->$orig(@args) });
};
around dispatch => sub {
my ($orig, $self, @args) = (@_);
my $dir = $self->model('DB')->schema->kiokudb_handle;
return $dir->txn_do(
scope => 1,
body => sub { $self->$orig(@args) },
);
};
# in MyApp.pm
use CatalystX::RoleApplicator;
__PACKAGE__->apply_request_class_roles(qw[
Catalyst::TraitFor::Request::REST::ForBrowsers
]);
# in action
if ($c->request->looks_like_browser) { ... }
# in MyApp.pm
use CatalystX::InjectComponent;
after setup_components => sub {
my $class = shift;
CatalystX::InjectComponent->inject(
into => $class,
component => 'Lynx::Debug::Controller::Login::As',
)
} if Lynx::Util::mode() eq 'dev';
use Catalyst::Controller::Accessors; cat_has user => ( is => 'ro', namespace => 'Lynx::Controller::User', ); cat_has role => ( is => 'rw' );
# in action
sub role {
my ($self, $c, $id) = @_;
$self->role($c,
$self->user($c)->roles->find($id)
);
# ...
}
/
#