CGI-Application
view release on metacpan or search on metacpan
t/default_runmode.t
t/mailform.t
t/prerun.t
t/getquery.t
t/header_props.t
t/arrayrefmodes.t
t/enhancement31.t
t/postrun.t
t/zerorm.t
t/errormode.t
t/callbacks.t
t/mode_param_path_info.t
t/mode_param_overwritten.t
t/load_tmpl_hook.t
t/query.t
t/run_as_psgi.t
t/lib/TestApp.pm
t/lib/TestApp2.pm
t/lib/TestApp3.pm
t/lib/TestApp4.pm
t/lib/TestApp5.pm
lib/CGI/Application.pm view on Meta::CPAN
L<CGI::Application::Plugin::ValidateRM> for an example.
In order to avoid namespace conflicts within a CGI::Application object,
plugin developers are recommended to use a unique prefix, such as the
name of plugin package, when storing information. For instance:
$app->{__PARAM} = 'foo'; # BAD! Could conflict.
$app->{'MyPlugin::Module::__PARAM'} = 'foo'; # Good.
$app->{'MyPlugin::Module'}{__PARAM} = 'foo'; # Good.
=head2 Writing Advanced Plug-ins - Using callbacks
When writing a plug-in, you may want some action to happen automatically at a
particular stage, such as setting up a database connection or initializing a
session. By using these 'callback' methods, you can register a subroutine
to run at a particular phase, accomplishing this goal.
B<Callback Examples>
# register a callback to the standard CGI::Application hooks
# one of 'init', 'prerun', 'postrun', 'teardown' or 'load_tmpl'
lib/CGI/Application.pm view on Meta::CPAN
# Object-based: callback will only last for lifetime of this object
$self->add_callback('prerun', \&some_method);
# If you want to create a new hook location in your application,
# You'll need to know about the following two methods to create
# the hook and call it.
# Create a new hook
$self->new_hook('pretemplate');
# Then later execute all the callbacks registered at this hook
$self->call_hook('pretemplate');
B<Callback Methods>
=head3 add_callback()
$self->add_callback ('teardown', \&callback);
$class->add_callback('teardown', 'method');
The add_callback method allows you to register a callback
function that is to be called at the given stage of execution.
Valid hooks include 'init', 'prerun', 'postrun' and 'teardown',
'load_tmpl', and any other hooks defined using the C<new_hook>
method.
The callback should be a reference to a subroutine or the name of a
method.
If multiple callbacks are added to the same hook, they will all be
executed one after the other. The exact order depends on which class
installed each callback, as described below under B<Callback Ordering>.
Callbacks can either be I<object-based> or I<class-based>, depending
upon whether you call C<add_callback> as an object method or a class
method:
# add object-based callback
$self->add_callback('teardown', \&callback);
# add class-based callbacks
$class->add_callback('teardown', \&callback);
My::Project->add_callback('teardown', \&callback);
Object-based callbacks are stored in your web application's C<$c>
object; at the end of the request when the C<$c> object goes out of
scope, the callbacks are gone too.
Object-based callbacks are useful for one-time tasks that apply only to
the current running application. For instance you could install a
C<teardown> callback to trigger a long-running process to execute at the
end of the current request, after all the HTML has been sent to the
browser.
Class-based callbacks survive for the duration of the running Perl
process. (In a persistent environment such as C<mod_perl> or
C<PersistentPerl>, a single Perl process can serve many web requests.)
Class-based callbacks are useful for plugins to add features to all web
applications.
Another feature of class-based callbacks is that your plugin can create
hooks and add callbacks at any time - even before the web application's
C<$c> object has been initialized. A good place to do this is in
your plugin's C<import> subroutine:
package CGI::Application::Plugin::MyPlugin;
use base 'Exporter';
sub import {
my $caller = scalar(caller);
$caller->add_callback('init', 'my_setup');
goto &Exporter::import;
}
lib/CGI/Application.pm view on Meta::CPAN
push @{ $INSTALLED_CALLBACKS{$hook}{$class} }, $callback;
}
}
=head3 new_hook(HOOK)
$self->new_hook('pretemplate');
The C<new_hook()> method can be used to create a new location for developers to
register callbacks. It takes one argument, a hook name. The hook location is
created if it does not already exist. A true value is always returned.
For an example, L<CGI::Application::Plugin::TT> adds hooks before and after every
template is processed.
See C<call_hook(HOOK)> for more details about how hooks are called.
=cut
sub new_hook {
my ($class, $hook) = @_;
$INSTALLED_CALLBACKS{$hook} ||= {};
return 1;
}
=head3 call_hook(HOOK)
$self->call_hook('pretemplate', @args);
The C<call_hook> method is used to executed the callbacks that have been registered
at the given hook. It is used in conjunction with the C<new_hook> method which
allows you to create a new hook location.
The first argument to C<call_hook> is the hook name. Any remaining arguments
are passed to every callback executed at the hook location. So, a stub for a
callback at the 'pretemplate' hook would look like this:
sub my_hook {
my ($c,@args) = @_;
# ....
}
Note that hooks are semi-public locations. Calling a hook means executing
callbacks that were registered to that hook by the current object and also
those registered by any of the current object's parent classes. See below for
the exact ordering.
=cut
sub call_hook {
my $self = shift;
my $app_class = ref $self || $self;
my $hook = lc shift;
my @args = @_;
die "Unknown hook ($hook)" unless exists $INSTALLED_CALLBACKS{$hook};
my %executed_callback;
# First, run callbacks installed in the object
foreach my $callback (@{ $self->{__INSTALLED_CALLBACKS}{$hook} }) {
next if $executed_callback{$callback};
eval { $self->$callback(@args); };
$executed_callback{$callback} = 1;
die "Error executing object callback in $hook stage: $@" if $@;
}
# Next, run callbacks installed in class hierarchy
# Cache this value as a performance boost
$self->{__CALLBACK_CLASSES} ||= [ Class::ISA::self_and_super_path($app_class) ];
# Get list of classes that the current app inherits from
foreach my $class (@{ $self->{__CALLBACK_CLASSES} }) {
# skip those classes that contain no callbacks
next unless exists $INSTALLED_CALLBACKS{$hook}{$class};
# call all of the callbacks in the class
foreach my $callback (@{ $INSTALLED_CALLBACKS{$hook}{$class} }) {
next if $executed_callback{$callback};
eval { $self->$callback(@args); };
$executed_callback{$callback} = 1;
die "Error executing class callback in $hook stage: $@" if $@;
}
}
}
=pod
B<Callback Ordering>
Object-based callbacks are run before class-based callbacks.
The order of class-based callbacks is determined by the inheritance tree of the
running application. The built-in methods of C<cgiapp_init>, C<cgiapp_prerun>,
C<cgiapp_postrun>, and C<teardown> are also executed this way, according to the
ordering below.
In a persistent environment, there might be a lot of applications
in memory at the same time. For instance:
CGI::Application
Other::Project # uses CGI::Application::Plugin::Baz
Other::App # uses CGI::Application::Plugin::Bam
lib/CGI/Application.pm view on Meta::CPAN
Plugin init callback
------ -------------
CGI::Application::Plugin::Baz baz_startup
CGI::Application::Plugin::Bam bam_startup
CGI::Application::Plugin::Foo foo_startup
CGI::Application::Plugin::Bar bar_startup
When C<My::App> runs, only C<foo_callback> and C<bar_callback> will
run. The other callbacks are skipped.
The C<@ISA> list of C<My::App> is:
My::App
My::Project
CGI::Application
This order determines the order of callbacks run.
When C<call_hook('init')> is run on a C<My::App> application, callbacks
installed by these modules are run in order, resulting in:
C<bar_startup>, C<foo_startup>, and then finally C<cgiapp_init>.
If a single class installs more than one callback at the same hook, then
these callbacks are run in the order they were registered (FIFO).
=cut
=head1 COMMUNITY
Therese are primary resources available for those who wish to learn more
about CGI::Application and discuss it with others.
t/callbacks.t view on Meta::CPAN
'teardown/My::App::my_app_teardown', # My::App (but installed in object)
'teardown/CGI::Application::Plugin::Bar::bar_teardown', # CAP::Bar
'teardown/CGI::Application::Plugin::Foo::foo_teardown', # CAP::Foo
'foo_hook/CGI::Application::Plugin::Foo::foo_custom', # CAP::Foo
'teardown/My::App::teardown', # My::App (but installed via CGI::Application)
);
is_deeply(\@Event_History, \@expected_events, 'My::App - callbacks executed correctly (first run)')
or do {
use Data::Dumper;
print STDERR "Actual Event History: \n";
print STDERR Dumper \@Event_History;
};
# Second run of My::App : the callback registered directly in self are
# no longer installed
@Event_History = ();
t/callbacks.t view on Meta::CPAN
'teardown/My::App::my_app_teardown', # My::App (but installed in object)
'teardown/CGI::Application::Plugin::Bar::bar_teardown', # CAP::Bar
'teardown/CGI::Application::Plugin::Foo::foo_teardown', # CAP::Foo
'foo_hook/CGI::Application::Plugin::Foo::foo_custom', # CAP::Foo
'teardown/My::App::teardown', # My::App (but installed via CGI::Application)
);
is_deeply(\@Event_History, \@expected_events, 'My::App - callbacks executed correctly (second run)')
or do {
use Data::Dumper;
print STDERR "Actual Event History: \n";
print STDERR Dumper \@Event_History;
};
t/callbacks.t view on Meta::CPAN
'postrun/CGI::Application::Plugin::Baz::baz_postrun', # CAP::Baz
'postrun/Other::App::cgiapp_postrun', # Other::App (but installed via CGI::Application)
# teardown
'teardown/CGI::Application::Plugin::Bam::bam_teardown', # CAP::Bam
'teardown/CGI::Application::Plugin::Baz::baz_teardown', # CAP::Baz
'teardown/Other::App::teardown', # Other::App (but installed via CGI::Application)
);
is_deeply(\@Event_History, \@expected_events, 'Other::App - callbacks executed correctly')
or do {
use Data::Dumper;
print STDERR "Actual Event History: \n";
print STDERR Dumper \@Event_History;
};
@Event_History = ();
Unrelated::App->new->run;
t/callbacks.t view on Meta::CPAN
'runmode/Unrelated::App::begin', # Unrelated::App
# postrun
'postrun/Unrelated::App::cgiapp_postrun', # Unrelated::App (but installed via CGI::Application)
# teardown
'teardown/Unrelated::App::teardown', # Unrelated::App (but installed via CGI::Application)
);
is_deeply(\@Event_History, \@expected_events, 'Unrelated::App - callbacks executed correctly')
or do {
use Data::Dumper;
print STDERR "Actual Event History: \n";
print STDERR Dumper \@Event_History;
};
( run in 0.628 second using v1.01-cache-2.11-cpan-9b1e4054eb1 )