Version 0.3
[blog.pm-common-perl-mods.git] / MojoX-Dispatcher-FilterChain / lib / MojoX / Dispatcher / FilterChain.pm
blob38df3c3c31426bb1b1291a5d45e0713f79215c5f
1 package MojoX::Dispatcher::FilterChain;
3 use strict;
4 use warnings;
6 use base 'Mojo::Base';
8 use MojoX::FilterChain::Constants;
10 our $VERSION = '0.03';
12 use constant DEBUG => $ENV{MOJOX_DISPATCHER_FILTERCHAIN_DEBUG} || 0;
14 __PACKAGE__->attr('filters', default => sub { [] });
16 sub add {
17 my $self = shift;
18 my $filter = shift;
20 my $name = ref $filter;
21 warn "Adding filter '$name'" if DEBUG;
23 push @{$self->filters}, $filter;
26 sub process {
27 my $self = shift;
29 foreach my $filter (@{$self->filters}) {
30 my $name = ref $filter;
32 warn "Running '$name' filter" if DEBUG;
34 my $proceed = $filter->run(@_);
36 warn "Stop filter chain after '$name' filter"
37 if DEBUG and $proceed == LAST;
39 last if $proceed == LAST;
44 __END__
46 =head1 NAME
48 MojoX::Dispatcher::FilterChain - Intercepting filter manager
50 =head1 SYNOPSIS
52 use MojoX::Dispatcher::FilterChain;
54 my $chain = MojoX::Dispatcher::FilterChain->new();
55 $chain->add(LanguageDetect->new);
56 $chain->add(Authorization->new);
57 $chain->add(RenderView->new);
59 ...
61 $chain->process($c);
63 =head1 DESCRIPTION
65 L<MojoX::Dispatcher::FilterChain> is a intercepting filter manager pattern
66 implementation.
68 Standart dispatch process can look like this:
70 sub dispatch {
71 my ($self, $c) = @_;
73 # Try to find a static file
74 $self->static->dispatch($c);
76 # Use routes if we don't have a response code yet
77 $self->routes->dispatch($c) unless $c->res->code;
79 # Nothing found, serve static file "public/404.html"
80 unless ($c->res->code) {
81 #$self->static->serve($c, '/404.html');
82 #$c->res->code(404);
86 Problem is that we have repetitive code that is checking whether to go to the
87 next dispatcher or stop.
89 What we want to have is a list of independent filters that are called in
90 specific order and one of them can intercept the chain.
92 Now we can rewrite our dispatch example.
94 __PACKAGE__->attr('chain',
95 default => sub { MojoX::Dispatcher::FilterChain->new } );
97 sub dispatch {
98 my ($self, $c) = @_;
100 # run filter chain
101 $self->chain->process($c);
104 sub startup {
105 my $self = shift;
107 my $chain = $self->chain;
109 $chain->add(MyApp::FilterChain::StaticDispatch->new($c));
110 $chain->add(MyApp::FilterChain::RoutesDispatch->new($c));
111 $chain->add(MyApp::FilterChain::RenderView->new($c));
114 Filter itself inherits L<MojoX::FilterChain::Base> and has method B<run> that
115 is called when chain is processed. L<MojoX::FilterChain::Constants>
116 module exports two self explaining constants B<NEXT> and B<LAST>. Depending on
117 which value is returned after running current filter, chain proceeds or stops.
119 Regular filter can look like this:
121 package MyApp::FilterChain::Routes;
123 use strict;
124 use warnings;
126 use base 'MojoX::FilterChain::Base';
128 # export LAST and NEXT constants
129 use MojoX::FilterChain::Constants;
131 sub run {
132 my ( $self, $c ) = @_;
134 $c->app->routes->dispatch($c);
136 return $c->res->code ? LAST : NEXT;
141 =head1 METHODS
143 L<MojoX::Dispatcher::FilterChain> inherits all methods from L<Mojo::Base> and
144 implements the following the ones.
146 =head2 C<new>
148 my $chain = MojoX::Dispatcher::FilterChain->new;
150 =head2 C<add>
152 Add filter instance to filter chain.
154 my $chain->add(Filter->new);
156 =head2 C<process>
158 Run filter chain. Parameters provided will be passed on to every filter.
160 $chain->process($c);
163 =head1 COPYRIGHT & LICENSE
165 Copyright 2008 Viacheslav Tikhanovskii, all rights reserved.
167 This program is free software; you can redistribute it and/or modify it
168 under the same terms as Perl itself.
170 =cut