- Fix RT #46760
- Fix RT #46618
- Fix typos
- - Replace reference to deprecated CatalystX::ListFramework::Builder with Catalyst::Plugin::AutoCRUD
+ - Replace reference to deprecated CatalystX::ListFramework::Builder
+ with Catalyst::Plugin::AutoCRUD
+ - Update development process / core team docs
+ - Cookbook fixes WRT authorization
+ - Better description of application setup process
+ - Fix some links
+ - Normalise spacing
5.8000 27 May 2009
- Tutorial:
+use strict;
+use warnings;
use inc::Module::Install 0.87;
+BEGIN {
+ require 'Module::Install::AuthorRequires';
+}
+
name 'Catalyst-Manual';
all_from 'lib/Catalyst/Manual.pm';
author 'Kieren Diment <zarquon@cpan.org>';
license 'perl';
-requires 'Test::More';
+test_requires 'Test::More';
+
+author_requires 'Test::Pod';
+author_requires 'Test::Pod::Coverage';
auto_install;
-resources repository => 'http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Manual/5.70/trunk/';
+resources repository => 'http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Manual/5.80/trunk/';
WriteAll;
+
Catalyst makes it easy to do all of these tasks, and many more. It is
extremely flexible in terms of what it allows you to do, and very fast.
-It has a very large number of "plugins" that interact with existing Perl
+It has a large number of "components" and "plugins" that interact with existing Perl
modules so that you can easily use them from within your
-application.
+application.
=over 4
-=item * Interact with a web server?
+=item * Interact with a web server?
Catalyst lets you use a number of different ones, and even comes with a
built-in server for testing or local deployment.
-=item * Do something based on a URI?
+=item * Do something based on a URI?
Catalyst has extremely flexible systems for figuring out what to do
based on a URI.
Catalyst has many plugins for different databases and database
frameworks, and for other non-database storage systems.
-=item * Handle forms?
+=item * Handle forms?
Catalyst has plugins available for several form creation and validation
systems that make it easy for the programmer to manage.
Catalyst has plugins available for a number of template modules and
other output packages.
-=item * Manage users?
+=item * Manage users?
Catalyst has plugins that handle sessions, authentication, and
authorization, in any way you need.
-=item * Developing the application?
+=item * Developing the application?
Catalyst has detailed logging built-in, which you can configure as
necessary, and supports the easy creation of new tests--some of which
Catalyst::Manual::CatalystAndMoose - How Catalyst 5.8+ and Moose relate
-
=head1 DESCRIPTION
-Since version 5.8 the core of Catalyst is based on L<Moose>. Although
-the developers went through great lengths to allow for a seamless
-transition, there are still a few things to keep in mind when trying
+Since version 5.8 the core of Catalyst is based on L<Moose>. Although
+the developers went through great lengths to allow for a seamless
+transition, there are still a few things to keep in mind when trying
to exploit the power of L<Moose> in your Catalyst application.
-This document provides you with a short overview of common caveats and
+This document provides you with a short overview of common caveats and
best practices to use L<Moose>-based classes within Catalyst.
A Moose-ified version of the context class should look like this:
package MyApp;
-
+
use Moose;
use namespace::autoclean;
use Catalyst (
# your roles and plugins
);
-
+ extends 'Catalyst';
+
+ # If you want to use method modifiers to adjust the setup process, (e.g. setup_finalize)
+ # they must be here, before the call to setup (advanced users only)
+
$app->config( name => 'MyApp' );
$app->setup;
-
- # method modifiers must be created after setup because otherwise they will
+
+ # method modifiers generally must be created after setup because otherwise they will
# conflict with plugin overrides
-
+
after 'finalize' => sub{
my $c = shift;
$c->log->info( 'done!' );
}
-You should also be aware, that roles in C<< $c-E<gt>setup >> are applied
-after the last plugin with all the benefits of using a single
+You should also be aware, that roles in C<< $c-E<gt>setup >> are applied
+after the last plugin with all the benefits of using a single
C<< with() >> statement in an ordinary L<Moose> class.
-Your class is automatically made immutable at the end of the current file.
+Your class is automatically made immutable at the end of the current file.
-CAVEAT: Using roles in C<< $c-E<gt>setup >> was implemented in Catalyst
+CAVEAT: Using roles in C<< $c-E<gt>setup >> was implemented in Catalyst
version 5.80004. In prior versions you might get away with
after 'setup_plugins' => sub{ with(
# your roles
)};
-
+
$app->setup(
# your plugins
);
-but this is discouraged and you should upgrade to 5.80004 anyway,
-because it fixes a few important regression against 5.71
+but this is discouraged and you should upgrade to 5.80004 anyway,
+because it fixes a few important regressions against 5.71
CAVEAT: Using roles in C<< $c-E<gt>setup >> will not currently allow
you to pass parameters to roles, or perform conflict resolution.
=head2 ACCESSORS
-Most of the request-specific attributes like C<$c-E<gt>stash>,
-C<$c-E<gt>request> and C<$c-E<gt>response> have been converted to
-L<Moose> attributes but without type constraints, attribute helpers or
-builder methods. This ensures that Catalyst 5.8 is fully backwards
-compatible to applications using the published API of Catalyst 5.7 but
-slightly limits the gains that could be had by wielding the full power
+Most of the request-specific attributes like C<$c-E<gt>stash>,
+C<$c-E<gt>request> and C<$c-E<gt>response> have been converted to
+L<Moose> attributes but without type constraints, attribute helpers or
+builder methods. This ensures that Catalyst 5.8 is fully backwards
+compatible to applications using the published API of Catalyst 5.7 but
+slightly limits the gains that could be had by wielding the full power
of L<Moose> attributes.
-Most of the accessors to information gathered during compile time is
-managed by C<Catalyst::ClassData>, which is a L<Moose>-aware version
-of L<Class::Data::Inheritable> but not compatible with
+Most of the accessors to information gathered during compile time is
+managed by C<Catalyst::ClassData>, which is a L<Moose>-aware version
+of L<Class::Data::Inheritable> but not compatible with
L<MooseX::ClassAttribute>.
-
=head2 ROLES AND METHOD MODIFIERS
-Since the release of Catalyst version 5.8 the only reason for creating
-a Catalyst extension as a plugin is to provide backward compatibility
+Since the release of Catalyst version 5.8, the only reason for creating
+a Catalyst extension as a plugin is to provide backward compatibility
to applications still using version 5.7.
-If backward compatibility is of no concern to you, you could as easily
-rewrite your plugins as roles and enjoy all the benefits of automatic
-method re-dispatching of C<< before >> and C<< after >> method
+If backward compatibility is of no concern to you, you could as easily
+rewrite your plugins as roles and enjoy all the benefits of automatic
+method re-dispatching of C<< before >> and C<< after >> method
modifiers, naming conflict detecting and generally cleaner code.
Plugins and roles should never use
after 'setup_finalize' => sub { ... } # this will work
-to run their own setup code if needed. If they need to influence the
-setup process itself, they can modify C<< setup_dispatcher() >>,
-C<< setup_engine() >>, C<< setup_stats() >>, C<< setup_components() >>
-and C<< setup_actions() >>, but this should be done with due
+to run their own setup code if needed. If they need to influence the
+setup process itself, they can modify C<< setup_dispatcher() >>,
+C<< setup_engine() >>, C<< setup_stats() >>, C<< setup_components() >>
+and C<< setup_actions() >>, but this should be done with due
consideration and as late as possible.
-
=head1 CONTROLLERS
-To activate Catalyst's action attributes, Moose-ified controller
-classes need to extend L<Catalyst::Controller> at compile time before
+To activate Catalyst's action attributes, Moose-ified controller
+classes need to extend L<Catalyst::Controller> at compile time before
the actions themselves are declared:
package Catalyst::Controller::Root;
use namespace::autoclean;
BEGIN { extends 'Catalyst::Controller'; }
- with qw(
+ with qw(
# your controller roles
);
-
=head2 Controller Roles
It is possible to use roles to apply method modifiers on controller actions
=head3 EXAMPLE
- use parent qw/Catalyst/;
+ package MyApp;
+ use Moose;
+ use namespace::autoclean;
+
use Catalyst qw/
Session
Session::Store::FastMmap
Session::State::Cookie
/;
+ extends 'Catalyst';
+ __PACKAGE__->setup;
-
+ package MyApp::Controller::Foo;
+ use Moose;
+ use namespace::autoclean;
+ BEGIN { extends 'Catalyst::Controller';
## Write data into the session
sub add_item : Local {
}
}
-
-=head2 Role-based Authorization
-
-For more advanced access control, you may want to consider using role-based
-authorization. This means you can assign different roles to each user, e.g.
-"user", "admin", etc.
-
-The C<login> and C<logout> methods and view template are exactly the same as
-in the previous example.
-
-The L<Catalyst::Plugin::Authorization::Roles> plugin is required when
-implementing roles:
-
- use parent qw/Catalyst/;
- use Catalyst qw/
- Authentication
- Authentication::Credential::Password
- Authentication::Store::Htpasswd
- Authorization::Roles/;
-
-Roles are implemented automatically when using
-L<Catalyst::Authentication::Store::Htpasswd>:
-
- # no additional role configuration required
- __PACKAGE__->config->{authentication}{htpasswd} = "passwdfile";
-
-Or can be set up manually when using L<Catalyst::Authentication::Store::DBIC>:
-
- # Authorization using a many-to-many role relationship
- __PACKAGE__->config->{authorization}{dbic} = {
- 'role_class' => 'My::Model::DBIC::Role',
- 'role_field' => 'name',
- 'user_role_user_field' => 'user',
-
- # DBIx::Class only (omit if using Class::DBI)
- 'role_rel' => 'user_role',
-
- # Class::DBI only, (omit if using DBIx::Class)
- 'user_role_class' => 'My::Model::CDBI::UserRole'
- 'user_role_role_field' => 'role',
- };
+=head2 FIXME
To restrict access to any action, you can use the C<check_user_roles> method:
my ( $self, $c ) = @_;
$c->assert_user_roles( qw/ user admin / );
}
-
+
=head2 Authentication/Authorization
This is done in several steps:
=head3 Logging in
When you have chosen your modules, all you need to do is call the C<<
-$c->login >> method. If called with no parameters, it will try to find
+$c->authenticate >> method. If called with no parameters, it will try to find
suitable parameters, such as B<username> and B<password>, or you can
pass it these values.
=head3 EXAMPLE
- use parent qw/Catalyst/;
+ package MyApp;
+ use Moose;
+ use namespace::autoclean;
+ extends qw/Catalyst/;
use Catalyst qw/Authentication
- Authentication::Credential::Password
- Authentication::Store::Htpasswd
Authorization::Roles/;
- __PACKAGE__->config->{authentication}{htpasswd} = "passwdfile";
-
- sub login : Local {
+ __PACKAGE__->config(
+ 'Plugin::Authentication' => {
+ default => {
+ credential => {
+ class => 'Htpasswd',
+ # FIXME
+ },
+ store => {
+ class => 'Null',
+ },
+ },
+ },
+ );
+
+ sub login : Local {
my ($self, $c) = @_;
if ( my $user = $c->req->param("user")
and my $password = $c->req->param("password") )
{
- if ( $c->login( $user, $password ) ) {
+ if ( $c->authenticate( username => $user, password => $password ) ) {
$c->res->body( "hello " . $c->user->name );
} else {
# login incorrect
e.g.,
+ # FIXME - Out of date
use Catalyst::Plugin::Authentication::Store::Minimal::Backend;
# Sets up the user `test_user' with password `test_pass'
use parent qw/Catalyst/;
use Catalyst qw/
- Authentication # yadda yadda
+ Authentication
Authorization::Roles
/;
sub connection {
my ($self, @rest) = @_;
$self->next::method(@rest);
- # $self is now a live My::Schema object, complete with DB connection
+ # $self is now a live My::Schema object, complete with DB connection
$self->ACCESSORNAME1([ $self->resultset('RESULTSOURCEMONIKER')->all ]);
$self->ACCESSORNAME2([ $self->resultset('RESULTSOURCEMONIKER')->search({ COLUMN => { '<' => '30' } })->all ]);
my ( $self, $c, $a, $b ) = @_;
return RPC::XML::int->new( $a + $b );
}
-
-
=head1 Views
=over
-=item
+=item
INCLUDE_PATH defines the directories that Template Toolkit should search
for the template files.
L<http://search.cpan.org/perldoc?Template>
-=head2 Adding RSS feeds
+=head2 Adding RSS feeds
Adding RSS feeds to your Catalyst applications is simple. We'll see two
different aproaches here, but the basic premise is that you forward to
$c->stash->{template}='rss.tt';
}
-Then you need a template. Here's the one from Agave:
+Then you need a template. Here's the one from Agave:
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
[% WHILE (post = posts.next) %]
<item>
<title>[% post.title %]</title>
- <description>[% post.formatted_teaser|html%]</description>
+ <description>[% post.formatted_teaser|html%]</description>
<pubDate>[% post.pub_date %]</pubDate>
<guid>[% post.full_uri %]</guid>
<link>[% post.full_uri %]</link>
</item>
[% END %]
</channel>
- </rss>
+ </rss>
=head3 Using XML::Feed
}
A little more code in the controller, but with this approach you're
-pretty sure to get something that validates.
+pretty sure to get something that validates.
Note that for both of the above aproaches, you'll need to set the
content type like this:
sub render : ActionClass('RenderView') { }
- sub end : Private {
+ sub end : Private {
my ( $self, $c ) = @_;
$c->forward('render');
# do stuff here
}
-
+
=head2 Action Types
=head3 Introduction
sub my_handles : Path('/handles') { .. }
-becomes
+becomes
http://localhost:3000/handles
http://localhost:3000/handles
-and
+and
http://localhost:3000/handles_and_other_parts
works for all unknown URLs, in this controller namespace, or every one
if put directly into MyApp.pm.
-=item index
+=item index
The index action is called when someone tries to visit the exact
namespace of your controller. If index, default and matching Path
sub begin : Private { .. }
-is called once when
+is called once when
http://localhost:3000/bucket/(anything)?
called. (In contrast, only one of the begin/end/default actions will
be called, the relevant one).
- package MyApp.pm;
+ package MyApp::Controller::Root;
sub auto : Private { .. }
-and
+and
sub auto : Private { .. }
-will both be called when visiting
+will both be called when visiting
http://localhost:3000/bucket/(anything)?
=head3 A word of warning
-Due to possible namespace conflicts with Plugins, it is advised to
-only put the pre-defined Private actions in your main MyApp.pm file,
-all others should go in a Controller module.
+You can put root actions in your main MyApp.pm file, but this is deprecated,
+please put your actions into your Root controller.
=head3 More Information
-L<http://search.cpan.org/author/SRI/Catalyst-5.61/lib/Catalyst/Manual/Intro.pod>
-
L<http://dev.catalyst.perl.org/wiki/FlowChart>
=head2 DRY Controllers with Chained actions.
=item B</cd/<ID>/track/<ID>>
Displays info on a particular track.
-
+
In the case of a multi-volume CD, this is the track sequence.
=item B</cd/<ID>/volume/<ID>/track/<ID>>
package CD::Controller;
use base qw/Catalyst::Controller/;
-
+
sub root : Chained('/') PathPart('/cd') CaptureArgs(1) {
my ($self, $c, $cd_id) = @_;
$c->stash->{cd_id} = $cd_id;
$c->stash->{cd} = $self->model('CD')->find_by_id($cd_id);
}
-
+
sub trackinfo : Chained('track') PathPart('') Args(0) RenderView {
my ($self, $c) = @_;
}
-
+
package CD::Controller::ByTrackSeq;
use base qw/CD::Controller/;
-
+
sub track : Chained('root') PathPart('track') CaptureArgs(1) {
my ($self, $c, $track_seq) = @_;
$c->stash->{track} = $self->stash->{cd}->find_track_by_seq($track_seq);
}
-
+
package CD::Controller::ByTrackVolNo;
use base qw/CD::Controller/;
-
+
sub volume : Chained('root') PathPart('volume') CaptureArgs(1) {
my ($self, $c, $volume) = @_;
$c->stash->{volume} = $volume;
}
-
+
sub track : Chained('volume') PathPart('track') CaptureArgs(1) {
my ($self, $c, $track_no) = @_;
$c->stash->{track} = $self->stash->{cd}->find_track_by_vol_and_track_no(
$c->stash->{volume}, $track_no
);
}
-
-Note that adding other actions (i.e. chain endpoints) which operate on a track
+
+Note that adding other actions (i.e. chain endpoints) which operate on a track
is simply a matter of adding a new sub to CD::Controller - no code is duplicated,
even though there are two different methods of looking up a track.
$c->req->args([qw/arg1 arg2 arg3/]);
$c->forward('/wherever');
-(See the L<Catalyst::Manual::Intro> Flow_Control section for more
+(See the L<Catalyst::Manual::Intro> Flow_Control section for more
information on passing arguments via C<forward>.)
=head2 Chained dispatch using base classes, and inner packages.
package MyApp::Controller::Base;
use base qw/Catalyst::Controller/;
- sub key1 : Chained('/')
+ sub key1 : Chained('/')
=head1 Deployment
=head4 1. Install Catalyst::Engine::Apache
-You should install the latest versions of both Catalyst and
+You should install the latest versions of both Catalyst and
Catalyst::Engine::Apache. The Apache engines were separated from the
Catalyst core in version 5.50 to allow for updates to the engine without
requiring a new Catalyst release.
PerlSwitches -I/var/www/MyApp/lib
PerlModule MyApp
-
+
<Location />
SetHandler modperl
PerlResponseHandler MyApp
SetHandler modperl
PerlResponseHandler MyApp
</Location>
-
+
When running this way, it is best to make use of the C<uri_for> method in
Catalyst for constructing correct links.
<Location /static>
SetHandler default-handler
</Location>
-
+
This will let all files within root/static be handled directly by Apache. In
a two-tiered setup, the frontend server should handle static files.
The configuration to do this on the frontend will vary.
FastCgiServer /var/www/MyApp/script/myapp_fastcgi.pl -processes 3
Alias /myapp/ /var/www/MyApp/script/myapp_fastcgi.pl/
-
+
# Or, run at the root
Alias / /var/www/MyApp/script/myapp_fastcgi.pl/
-
+
The above commands will launch 3 app processes and make the app available at
/myapp/
First, launch your app as a standalone server listening on a socket.
script/myapp_fastcgi.pl -l /tmp/myapp.socket -n 5 -p /tmp/myapp.pid -d
-
+
You can also listen on a TCP port if your web server is not on the same
machine.
script/myapp_fastcgi.pl -l :8080 -n 5 -p /tmp/myapp.pid -d
-
+
You will probably want to write an init script to handle starting/stopping
of the app using the pid file.
FastCgiExternalServer /tmp/myapp.fcgi -socket /tmp/myapp.socket
Alias /myapp/ /tmp/myapp.fcgi/
-
+
# Or, run at the root
Alias / /tmp/myapp.fcgi/
-
+
=head3 More Info
L<Catalyst::Engine::FastCGI>.
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
- # This is optional if you'd like to show a custom error page
+ # This is optional if you'd like to show a custom error page
# if the proxy is not available
ErrorDocument 502 /static/error_pages/http502.html
% perl Makefile.PL
% make catalyst_par
-You can customise the PAR creation process by special "catalyst_par_*" commands
-available from L<Module::Install::Catalyst>. You can add these commands in your
+You can customise the PAR creation process by special "catalyst_par_*" commands
+available from L<Module::Install::Catalyst>. You can add these commands in your
Makefile.PL just before the line containing "catalyst;"
- #Makefile.PL example with extra PAR options
+ #Makefile.PL example with extra PAR options
use inc::Module::Install;
name 'MyApp';
MyApp->config->{static}->{include_path} = [
MyApp->config->{root},
- '/path/to/my/files'
+ '/path/to/my/files'
];
When you override include_path, it will not automatically append the
be replaced easily:
MyApp->config->{static}->{ignore_extensions} = [
- qw/tmpl tt tt2 html xhtml/
+ qw/tmpl tt tt2 html xhtml/
];
=item Ignoring directories
sub end : Private {
my ( $self, $c ) = @_;
- $c->forward( 'MyApp::View::TT' )
+ $c->forward( 'MyApp::View::TT' )
unless ( $c->res->body || !$c->stash->{template} );
}
infrequently but may be viewed many times.
use Catalyst qw/Cache::FileCache/;
-
+
...
-
+
use File::stat;
sub render_pod : Local {
my ( self, $c ) = @_;
-
+
# the cache is keyed on the filename and the modification time
# to check for updates to the file.
my $file = $c->path_to( 'root', '2005', '11.pod' );
my $mtime = ( stat $file )->mtime;
-
+
my $cached_pod = $c->cache->get("$file $mtime");
if ( !$cached_pod ) {
$cached_pod = do_slow_pod_rendering();
}
$c->stash->{pod} = $cached_pod;
}
-
+
We could actually cache the result forever, but using a value such as 12 hours
allows old entries to be automatically expired when they are no longer needed.
sub front_page : Path('/') {
my ( $self, $c ) = @_;
-
+
$c->forward( 'get_news_articles' );
$c->forward( 'build_lots_of_boxes' );
$c->forward( 'more_slow_stuff' );
-
+
$c->stash->{template} = 'index.tt';
}
We can add the PageCache plugin to speed things up.
use Catalyst qw/Cache::FileCache PageCache/;
-
+
sub front_page : Path ('/') {
my ( $self, $c ) = @_;
-
+
$c->cache_page( 300 );
-
+
# same processing as above
}
-
+
Now the entire output of the front page, from <html> to </html>, will be
cached for 5 minutes. After 5 minutes, the next request will rebuild the
page and it will be re-cached.
headers for the cached page.
MyApp->config->{page_cache}->{set_http_headers} = 1;
-
+
This would now set the following headers so proxies and browsers may cache
the content themselves.
Cache-Control: max-age=($expire_time - time)
Expires: $expire_time
Last-Modified: $cache_created_time
-
+
=head3 Template Caching
Template Toolkit provides support for caching compiled versions of your
still be automatically detected.
package MyApp::View::TT;
-
+
use strict;
use warnings;
use base 'Catalyst::View::TT';
-
+
__PACKAGE__->config(
COMPILE_DIR => '/tmp/template_cache',
);
-
+
1;
-
+
=head3 More Info
See the documentation for each cache plugin for more details and other
=head2 Testing
-Catalyst provides a convenient way of testing your application during
+Catalyst provides a convenient way of testing your application during
development and before deployment in a real environment.
-C<Catalyst::Test> makes it possible to run the same tests both locally
+C<Catalyst::Test> makes it possible to run the same tests both locally
(without an external daemon) and against a remote server via HTTP.
=head3 Tests
=item C<02pod.t>
-Verifies that all POD is free from errors. Only executed if the C<TEST_POD>
+Verifies that all POD is free from errors. Only executed if the C<TEST_POD>
environment variable is true.
=item C<03podcoverage.t>
=back
-C<request> returns an instance of C<HTTP::Response> and C<get> returns the
+C<request> returns an instance of C<HTTP::Response> and C<get> returns the
content (body) of the response.
=head3 Running tests locally
mundus:~/MyApp chansen$ CATALYST_DEBUG=0 TEST_POD=1 prove --lib lib/ t/
- t/01app............ok
- t/02pod............ok
- t/03podcoverage....ok
+ t/01app............ok
+ t/02pod............ok
+ t/03podcoverage....ok
All tests successful.
Files=3, Tests=4, 2 wallclock secs ( 1.60 cusr + 0.36 csys = 1.96 CPU)
-
+
C<CATALYST_DEBUG=0> ensures that debugging is off; if it's enabled you
will see debug logs between tests.
=head3 Running tests remotely
mundus:~/MyApp chansen$ CATALYST_SERVER=http://localhost:3000/ prove --lib lib/ t/01app.t
- t/01app....ok
+ t/01app....ok
All tests successful.
Files=1, Tests=2, 0 wallclock secs ( 0.40 cusr + 0.01 csys = 0.41 CPU)
-C<CATALYST_SERVER=http://localhost:3000/> is the absolute deployment URI of
-your application. In C<CGI> or C<FastCGI> it should be the host and path
+C<CATALYST_SERVER=http://localhost:3000/> is the absolute deployment URI of
+your application. In C<CGI> or C<FastCGI> it should be the host and path
to the script.
=head3 C<Test::WWW::Mechanize> and Catalyst
Danijel Milicevic C<me@danijel.de>
-Viljo Marrandi C<vilts@yahoo.com>
+Viljo Marrandi C<vilts@yahoo.com>
Marcus Ramberg C<mramberg@cpan.org>
Jesse Sheidlower C<jester@panix.com>
-Andy Grundman C<andy@hybridized.org>
+Andy Grundman C<andy@hybridized.org>
Chisel Wright C<pause@herlpacker.co.uk>
The main current goals of the Catalyst core development team continue to
be stability, performance, and a more paced addition of features, with a
-focus on extensibility. Extensive improvements to the documentation are
-also expected in the short term.
+focus on extensibility.
The Catalyst Roadmap at
-L<http://dev.catalyst.perl.org/wiki/fromtrac/future/roadmap> will remain as is,
+L<http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Runtime/5.80/trunk/lib/Roadmap.pod>
+will remain as is,
and continues to reflect the specific priorities and schedule for future
releases.
=head2 Membership
The Catalyst Core Team consists of the developers that have full commit
-privileges to the entire Catalyst source tree.
+privileges to the entire Catalyst source tree.
In addition, the core team may accept members that have non-technical
roles such as marketing, legal, or economic responsibilities.
=item Matt S. Trout
+=item Florian Ragwitz
+
+=item Tomas Doran
+
=back
New members of the Core Team must be accepted by a 2/3 majority by the
Planned releases to CPAN should be performed by the release manager, at
the time of writing Marcus Ramberg, or the deputy release manager, at
-the time of writing Andy Grundman. In the case of critical error
+the time of writing Florian Ragwitz. In the case of critical error
correction, any member of the Core Team can perform a rescue release.
=head2 Public statements from the Core Team
=item 1
When the Catalyst module is imported in the main application
-module it evaluates any options (C<-Debug>, C<-Engine=XXX>)
-and loads any specified plugins, making the application module
+module it stores any options.
+
+
+=item 2
+
+WHen C<< __PACKAGE__->setup >> is called, it evaluates any
+options stored (C<-Debug>, C<-Engine=XXX>), makes the application
+inherit from L<Catalyst> (if that hasn't already been done with an
+explicit C<< use base 'Catalyst'; >> or C<< extends 'Catalyst'; >>.
+Any specified plugins are then loaded, the application module is made to
inherit from the plugin classes. It also sets up a default log
object and ensures that the application module inherits from
C<Catalyst> and from the selected specialized Engine module.
-=item 2
+=item 3
-When the application module makes the first call to C<< __PACKAGE__->action() >>
-(implemented in C<Catalyst::Engine>), Catalyst automatically loads all
+Catalyst automatically loads all
components it finds in the C<$class::Controller>, C<$class::C>,
C<$class::Model>, C<$class::M>, C<$class::View> and C<$class::V>
-namespaces (using C<Module::Pluggable>). A table of actions is built up
-and added to on subsequent calls to C<action()>.
+namespaces (using C<Module::Pluggable>). As each is loaded, if it has a
+L<Catalyst::Component/COMPONENT|COMPONENT> method then this method
+will be called, and passed that component's configuration. It then returns
+an instance of the component, which becomes the C<$self> when methods in
+that component are called later.
-=back
+=item 4
+
+Each controller has it's C<register_actions> method called. At this point,
+the subroutine attributes are retrieved from the
+L<MooseX::MethodAttributes::Role::Meta::Map|metaclass>, parsed, and used to
+build instances of L<Catalyst::Action>, which are then registered with
+the dispatcher.
+=back
=head2 Request Lifecycle
For each request Catalyst builds a I<context> object, which includes
information about the request, and then searches the action table for matching
-actions.
+actions.
The handling of a request can be divided into three stages: preparation of the
context, processing of the request, and finalization of the response. These
during the prepare phase, then push the generated response information down to
the underlying layer during the finalize phase.
-
=head1 AUTHOR
Sebastian Riedel, C<sri@oook.de>
This program is free software, you can redistribute it and/or modify it under
the same terms as Perl itself.
+
=head3 Install
-Installation of Catalyst can be a time-consuming effort, due to its
-large number of dependencies. Although most of the frustrations
-associated with this are now ironed out and a simple C<cpan
-Catalyst::Devel> or C<cpan Catalyst::Runtime> are now usually
-straightforward, if you still have problems, you can use use Matt
-Trout's C<cat-install> script, from
-L<http://www.shadowcatsystems.co.uk/static/cat-install>, and then
-install L<Catalyst::Devel>.
-
- # perl cat-install
+Installation of Catalyst should be straightforward:
+
+ # perl -MCPAN -e 'install Catalyst::Runtime'
# perl -MCPAN -e 'install Catalyst::Devel'
=head3 Setup
many L</Models>, L</Views>, and L</Controllers> as you like. As discussed
previously, the general idea is that the View is responsible for the
output of data to the user (typically via a web browser, but a View can
-also generate PDFs or e-mails, for example); the Model is responsible
+also generate PDFs or e-mails, for example); the Model is responsible
for providing data (typically from a relational database); and the
Controller is responsible for interacting with the user and deciding
how user input determines what actions the application takes.
In the world of MVC, there are frequent discussions and disagreements
about the nature of each element - whether certain types of logic
belong in the Model or the Controller, etc. Catalyst's flexibility
-means that this decision is entirely up to you, the programmer;
+means that this decision is entirely up to you, the programmer;
Catalyst doesn't enforce anything. See L<Catalyst::Manual::About> for
a general discussion of these issues.
common class methods like C<config> and C<new> (constructor).
package MyApp::Controller::Catalog;
+ use Moose;
+ use namespace::autoclean;
- use strict;
- use base 'Catalyst::Controller';
+ BEGIN { extends 'Catalyst::Controller' }
__PACKAGE__->config( foo => 'bar' );
=over 4
-=item * B<MyApp/Model/>
+=item * B<MyApp/Model/>
=item * B<MyApp/M/>
In older versions of Catalyst, the recommended practice (and the one
automatically created by helper scripts) was to name the directories
-C<M/>, C<V/>, and C<C/>. Though these still work, we now recommend
-the use of the full names.
+C<M/>, C<V/>, and C<C/>. Though these still work, they are deprecated
+and we now recommend the use of the full names.
=head4 Views
sub view : Global {
my ( $self, $c, $id ) = @_;
-
+
$c->stash->{item} = $c->model('MyModel::Foo')->find($id);
}
1;
-
+
sub end : Private {
my ( $self, $c ) = @_;
-
+
$c->stash->{template} ||= 'index.tt';
$c->forward( $c->view('TT') );
}
# in a Controller
sub list : Local {
my ( $self, $c ) = @_;
-
+
$c->stash->{template} = 'list.tt';
-
+
use Some::Outside::Database::Module;
my @records = Some::Outside::Database::Module->search({
artist => 'Led Zeppelin',
});
-
+
$c->stash->{records} = \@records;
}
=item * Namespace-prefixed (C<:Local>)
- package MyApp::Controller::My::Controller;
+ package MyApp::Controller::My::Controller;
sub foo : Local { }
Matches any URL beginning with> http://localhost:3000/my/controller/foo. The namespace and
sub foo : Global { }
Matches http://localhost:3000/foo - that is, the action is mapped
-directly to the controller namespace, ignoring the function name.
+directly to the controller namespace, ignoring the function name.
C<:Global> is equivalent C<:Local> one level higher in
-the namespace.
+the namespace.
package MyApp::Controller::Root;
__PACKAGE__->config->{namespace}='';
to only match URLs starting /foo/bar/* - with one additional path
element required after 'bar'.
-NOTE that adding C<:Args(0)> and missing out :Args completely are B<not>
+NOTE that adding C<:Args(0)> and missing out :Args completely are B<not>
the same thing.
-C<:Args(0)> means that no arguments are taken. Thus, the URL and path must
+C<:Args(0)> means that no arguments are taken. Thus, the URL and path must
match precisely.
-No :Args at all means that B<any number> of arguments are taken. Thus, any
+No :Args at all means that B<any number> of arguments are taken. Thus, any
URL that B<starts with> the controller's path will match.
Actions with the C<:Local> attribute are similarly equivalent to
C<:Path('action_name')>:
- sub foo : Local { }
+ sub foo : Local { }
-is equivalent to
+is equivalent to
sub foo : Path('foo') { }
=item * Pattern-match (C<:Regex> and C<:LocalRegex>)
-
+
package MyApp::Controller::My::Controller;
sub bar : Regex('^item(\d+)/order(\d+)$') { }
that URL.
B<Note:> Looking at it another way, C<auto> actions have to return a
-true value to continue processing!
+true value to continue processing!
=head4 URL Path Handling
So Catalyst would never mistakenly dispatch the first two URLs to the
'^foo$' action.
-If a Regex or LocalRegex action doesn't use the '$' anchor, the action will
-still match a URL containing arguments; however the arguments won't be
+If a Regex or LocalRegex action doesn't use the '$' anchor, the action will
+still match a URL containing arguments; however the arguments won't be
available via C<@_>, because the Regex will 'eat' them.
Beware! If you write two matchers, that match the same path, with the
my $current_page = $c->req->param('page') || 1;
# multiple values for single parameter name
- my @values = $c->req->param('scrolling_list');
+ my @values = $c->req->param('scrolling_list');
# DFV requires a CGI.pm-like input hash
my $results = Data::FormValidator->check($c->req->params, \%dfv_profile);
=head1 AUTHOR
-Sebastian Riedel, C<sri@oook.de>
+Sebastian Riedel, C<sri@oook.de>
David Naughton, C<naughton@umn.edu>
Marcus Ramberg, C<mramberg@cpan.org>
Jesse Sheidlower, C<jester@panix.com>
This program is free software. You can redistribute it and/or modify it
under the same terms as Perl itself.
+
+=cut
+