2. Installing Catalyst
cpan/cpanm Task::Catalyst
● DBIx::Class Support
● Template::Toolkit Support
● Authentication/Authorization Support
● HTML::FormFu Support
OR install from apt-get
3. Setting up Catalyst App
catalyst gets rid of repeated work...
sheeju@sheeju-exceleron:~/projects$ catalyst.pl Library
created "Library"
created "Library/script"
created "Library/lib"
created "Library/root"
……...
created "Library/script/library_cgi.pl"
created "Library/script/library_fastcgi.pl"
created "Library/script/library_server.pl"
created "Library/script/library_test.pl"
created "Library/script/library_create.pl"
Change to application directory and Run "perl Makefile.PL" to make sure your install is complete
4. What is MVC
● Model (Data)
○ Get All Users
○ Get User foo
○ Delete User
● View (Display)
○ Render the page
○ Render user as JSON/XML
● Controller (Glue’s - model and view)
○ Get the Data from Model
○ Check Permission
○ Send data over to the view
5. So what does this mean?
* Is full CPAN package
* Contains Standalone and server deployment scripts
* loads config automatically
* testing stubs
* helpers to create more parts of your app
6. App Layout
● lib/ - package/class namespaces
○ Library - lib/Library.pm
○ Library::Controller::Root - lib/Library/Controller/Root.pm
○ Model & View - empty for purpose
● root/ - css,js,tt etc store here exposed via /static URL
● script/ - application level script goes here including dev server script
○ library_create.pl
○ library_server.pl
● t/ - Tests goes here (Watch for TDD presentation)
fires up app in own dedicated server http://localhost:3000
10. Request ⇔ Response
● All web applications handle request and generate responses.
● In Catalyst, this happens in special methods called "actions". On every request, Catalyst
identifies one or more actions and calls them with special arguments, including a reference to
the "context" object that provides a convenient and practical API through which everything
else is accomplished.
○ Actions are contained within classes called "controllers", which live in a special
path/namespace in the application
● script/library_create.pl controller Something - creates a new controller
○ The only reason to have more than one controller is for organization; you can put all
your actions in the Root controller with no loss of features or ability. Controllers are just
the containers for actions.
● In the following sections, I describe how Catalyst decides which actions to call on each request
("dispatch") and then explain how to use the supplied context object within them.
11. Dispatch
● Catalyst provides a particularly flexible and powerful mechanism for configuring dispatch rules.
● Rather than having a separate configuration to assign URLs to specific actions, Catalyst uses
the actions themselves to determine URL mappings dynamically.
● Each action definition (which is just a Perl subroutine) represents not only a block of code, but
also what URL paths apply to it. This is specified in subroutine attributes—a lesser-known Perl
feature that provides arbitrary labels that can be used for introspection.
● Catalyst supports a handful of parameterized attributes (Local,Global,Private,Path,
LocalRegex,Regex,Chained) to determine the URL path to action mappings in a variety ways
sub do_stuff :Attribute1 :Attribute2 :Attribute3('with_argument') { ...
Note The first : for the attributes is compulsory, whereas the
following are optional.
12. Dispatch :Path
:Path Attribute (Absolute Path)
sub myaction :Path('/some/place') {
my ( $self, $c, @args ) = @_;
# do stuff...
}
● Regardless of what controller you put it in, the above action would map to all URLs starting
with /some/place (http://localhost:3000/some/place with the development server).
● If you omitted the starting slash and used :Path('some/place'), the action would map to a path
relative to the namespace of the controller. For example, if it were in Library::Controller::
Foobar, it would be mapped to URL paths starting with /foobar/some/place.
13. Dispatch :Local
sub place :Local {
my ( $self, $c, @args ) = @_;
# do stuff...
}
● Instead of using :Path to set the path explicitly, you can set :Local to use the name of the
controller and method.
● For instance, the following action, if contained in the controller Library::Controller::Some,
would also map to /some/place:
● If it were contained in the controller Library::Controller::Some::Other, it would map to
/some/other/place.
14. Dispatch :Path/Local/* :Args
sub myaction :Path('/some/place') {
my ( $self, $c ) = @_;
# do stuff...
}
● Actions include subpaths by default, so the above also would match /some/place/blah/foo/1.
● When this happens, the leftover parts of the path are supplied as arguments to the action method
('blah','foo','1').
● You can use the :Args attribute to limit how deep the action will match subpaths, if at all.
● With an Args value of 0, this action would match only /some/place, but nothing below it:
sub myaction :Path('/some/place') :Args(0) {
my ( $self, $c ) = @_;
# do stuff...
}
15. Dispatch :Global & :Private
● :Global
○ works like :Local but ignores the controller name
○ Anywhere - show’s up in the root of your namespace
● :Private
○ Internal Functions
○ No URL
○ Can be invoked only through a $c->forward or a $c->detach within a
controller.
16. Dispatch :Regex/:LocalRegex
● path pattern matching, discouraged from
using.
● Explore yourself
● You can use Chained instead
17. Dispatch :Chained
● You can configure additional/multiple actions to be called with single requests in any order
you like.
package MyApp::Controller::Users;
use parent 'Catalyst::Controller';
# private
sub base :Chained("/") :PathPart("users") :CaptureArgs(0) {}
# match /users
sub root :Chained("base") :PathPart("") :Args(0) {}
# private
sub base_user : Chained('base') PathPart('') CaptureArgs(1) { ... }
# match /users/1
sub root_user : Chained('base_user') PathPart('') Args(0) { ... }
# match /users/1/edit
sub user_edit : Chained('base') PathPart('edit') Args(0) { ... }
# match /users/1/display
sub user_edit : Chained('base') PathPart('display') Args(0) { ... }
Users <id>
Edit
Display
URL’s like /users/1/edit, /users/1/display can separate the processing of /users/1 part into its own
method.
18. Dispatch Flow
● When a URL matches more than one action, Catalyst picks the one that matches best.
● Exceptions: Called at various stages of every request in addition to the matched action
○ sub default :Private {} - Match everything that doesn’t match
○ sub index :Private {}
○ sub begin :Private {}
○ sub end :Private {}
○ sub auto :Private {}
Eg URL: /person/sheeju
MyApp::C::Person -> sheeju (finds “sheeju” action inside “person” namespace)
MyApp::C::Person -> auto (When found)
MyApp::C::Root -> auto (if previous auto returs true continue to the next auto, else kill the request)
MyApp::C::Person -> begin (if there is controller’s begin or run Root’s begin)
MyApp::C::Person/Root -> end (Finally end, usually to render view)
21. The Context Object ($c)
● Controller actions serve as entry points to application code.
● A special per-request object called the "context" is supplied as an argument to every action
when it is called by the dispatcher.
● The context object typically is read into a variable named $c, but it could be called anything.
Important Objects
● Request ($c->req) – web paranaters, cookies, headers, uploaded files
● Response ($c->res) – set document body, HTTP status code
● Configuration ($c->config) – static project configuration
● Log ($c->log) – print log messages
● Stash ($c->stash) – pass data from model to view
● Session ($c->session) - session store
22. Controller: GET/POST Params
$c->req->method - To check the request method (GET/POST)
● GETs end up in passing parms
○ my ($self, $c, $get1, $get2, $get3 ) = @_; OR $c->req->params
● POSTs
○ my $params = $c->req-params;
❏ Pass data to models or store in db
❏ Get Manipulated data and pass it to View (HTML/JSON…)
https://metacpan.org/pod/Catalyst::Request
23. Controller Data Stores
1. Stash: short term, lasts one response cycle. Data are references, same
form as TT takes for its process() method.
2. Flash: longer term. Used often with the flash_to_stash config set. Useful
for storage when handling forms.
3. Session: lasts some time. Can last longer than visitor's login, 2 hrs by
default. Don't use same data names as stash, because they interact.
24. Data – Long Term Storage
● Usually handled with a database
○ But check out http://sedition.com/a/2794
○ The above shows how to read text files.
● Build your tables, and then use the database to build the ORM schema.
● script/library_create.pl model DB DBIC::Schema Library::Schema
create=static components=TimeStamp,EncodedColumn 'dbi:Pg:
dbname=sheeju sheeju sheeju '{ AutoCommit => 1 }'
25. View TT
● Web/HTML
perl script/library_create.pl view Web TT - creates simple TT view
perl script/library_create.pl view Web TTSite - creates TT site with layout, header, footer
● JSON - Catalyst::View::JSON
26. OK so now how to render?
● catalyst.pl has already done this for you
sub end: ActionClass(‘RenderView’) {}
● RenderView will try to render a template unless body is defined or
redirect is in place
● More than one view? $c->config->{default_view} or $c->stash->
{current_view} to decide which one to use
27. ActionClass & ActionRole
● ActionClass
○ A type of Controller that uses bottom-level namespace of an class as an argument to ActionClass
attribute
○ Catalyst::Action::RenderView - best example available on default project, execute method is called
○ Use Does instead
● ActionRole (Does)
○ Provides the :Does attribute which applies roles to your action class
○ provides “around execute”, “after execute”, “before execute” method using Moose Methodmodifiers
sub foo : Local Does('Moo') { ... } # Catalyst::ActionRole::
sub bar : Local Does('~Moo') { ... } # MyApp::ActionRole::Moo
sub baz : Local Does('+MyApp::ActionRole::Moo') { ... }
http://www.catalystframework.org/calendar/2012/16
http://metacpan.org/module/Catalyst::Controller::ActionRole
28. AJAX Dispatching
● See Demo on AJAX ActionRole
# Make sure this is an AJAX request
my $hdr_accept = $c->req->header('Accept') || '';
my $hdr_x_req_with = $c->req->header('X-Requested-With') || '';
if ( $hdr_accept ne 'application/json' && $hdr_x_req_with ne 'XMLHttpRequest')
{
$c->stash->{ajax} = 0;
return $self->$orig(@_);
}