File Coverage

blib/lib/WebNano/Controller.pm
Criterion Covered Total %
statement 72 72 100.0
branch 29 36 80.5
condition 9 12 75.0
subroutine 16 16 100.0
pod 8 8 100.0
total 134 144 93.0


line stmt bran cond sub pod time code
1 5     5   8388 use strict;
  5         24  
  5         162  
2 5     5   28 use warnings;
  5         9  
  5         235  
3              
4             package WebNano::Controller;
5             BEGIN {
6 5     5   88 $WebNano::Controller::VERSION = '0.007';
7             }
8              
9 5     5   1085 use URI::Escape 'uri_unescape';
  5         1553  
  5         326  
10 5     5   4846 use Plack::Request;
  5         346720  
  5         166  
11              
12 5     5   588 use WebNano::FindController 'find_nested';
  5         12  
  5         386  
13 5     5   31 use Object::Tiny::RW qw/ app env self_url url_map _req path /;
  5         10  
  5         49  
14              
15 70     70 1 1560 sub DEBUG { shift->app->DEBUG }
16              
17             sub req {
18 2     2 1 149 my $self = shift;
19 2 50       61 return $self->_req if defined $self->_req;
20 2         61 my $req = Plack::Request->new( $self->env );
21 2         82 $self->_req( $req );
22 2         23 return $req;
23             }
24              
25 8     8 1 30 sub template_search_path { [] }
26              
27             sub render {
28 19     19 1 115 my $self = shift;
29 19         548 return $self->app->renderer->render( c => $self, @_ );
30             }
31              
32             sub local_dispatch {
33 71     71 1 94 my ( $self ) = @_;
34 71         85 my @parts = @{ $self->path };
  71         1561  
35 71         601 my $name = uri_unescape( shift @parts );
36 71 100 66     793 $name = 'index' if !defined( $name ) || !length( $name );
37 71         74 my $action;
38 71 100       2023 if( my $map = $self->url_map ){
39 49 100       325 if( ref $map eq 'HASH' ){
40 41 100       110 $action = $self->can( $map->{$name} ) if $map->{$name};
41             }
42 49 100       151 if( ref $map eq 'ARRAY' ){
43 8 100       15 $action = $self->can( $name ) if grep { $_ eq $name } @$map;
  8         33  
44             }
45             }
46 71 100       604 $action = $self->can( $name . '_action' ) if !$action;
47 71 100       175 if( ! $action ){
48 37         806 my $method = uc( $self->env->{REQUEST_METHOD} );
49 37 50 66     439 $action = $self->can( $name . '_' . $method ) if $method eq 'GET' || $method eq 'POST';
50             }
51 71         204 my $out;
52 71 100       129 if( $action ){
53 35         101 $out = $action->( $self, @parts );
54             }
55 71 50 66     340 warn 'No local action found in "' . ref($self) . qq{" for "$name"\n} if !defined( $out ) && $self->DEBUG;
56 71         164 return $out;
57             }
58              
59              
60             sub _self_path{
61 35     35   48 my $class = shift;
62 35         40 my $path = $class;
63 35         146 $path =~ s/.*::Controller(?=(::|$))//;
64 35         46 $path =~ s{::}{/};
65 35         745 return $path . '/';
66             }
67              
68             sub dispatch_to_class {
69 35     35 1 52 my ( $self, $to ) = @_;
70 35 50       126 $to =~ s/::|'//g if defined( $to );
71 35 50       74 return if !length( $to );
72 35         54 my $class = ref $self;
73 35         96 my $controller_class = find_nested( $class->_self_path . $to, $self->app->controller_search_path );
74 34 100       113 if( !$controller_class ){
75 5 50       16 warn qq{No subcontroller found in "$class" for "} . $class->_self_path . $to. qq{"\n} if $self->DEBUG;
76 5         30 return;
77             }
78 29 50       76 warn qq{Dispatching to "$controller_class"\n} if $self->DEBUG;
79 29         595 return $controller_class->handle(
80             path => $self->path,
81             app => $self->app,
82             self_url => $self->{self_url} . $to. '/',
83             env => $self->env,
84             );
85             }
86              
87             sub handle {
88 71     71 1 648 my ( $class, %args ) = @_;
89 71         337 my $self = $class->new( %args );
90 71         2262 my $out = $self->local_dispatch();
91 71 100 100     606 return $out if defined( $out ) || !$self->search_subcontrollers;
92 35         155 my $path_part = shift @{ $self->path };
  35         670  
93 35         251 return $self->dispatch_to_class( $path_part );
94             }
95              
96 1     1 1 11 sub search_subcontrollers { 0 }
97              
98             1;
99              
100              
101              
102             =pod
103              
104             =head1 NAME
105              
106             WebNano::Controller - WebNano Controller
107              
108             =head1 VERSION
109              
110             version 0.007
111              
112             =head1 DESCRIPTION
113              
114             This is the WebNano base controller. It's handle method dispatches the request
115             to appropriate action method or to a next controller.
116              
117             The action method should return a string containing the HTML page,
118             a Plack::Response object or a code ref.
119              
120             If there is no suitable method in the current class and the method search_subcontrollers
121             returns a true value then child controller classes
122             are tried out. If there is found one that matches the path part then it is
123             instantiated with the current psgi env and it's handle method is called.
124              
125             In a path C all
126             C, C
127             and C need to
128             override search_subcontrollers method to return 1.
129              
130             =head1 SYNOPSIS
131             With Moose:
132              
133             package MyApp::Controller;
134            
135             use Moose;
136             use MooseX::NonMoose;
137              
138             extends 'WebNano::Controller';
139            
140             has '+url_map' => ( default => sub { { 'Mapped Url' => 'mapped_url' } } );
141            
142             sub index_action {
143             my $self = shift;
144             return $self->render( 'index.tt' );
145             }
146            
147             sub mapped_url { 'This is the mapped url page' }
148            
149             1;
150              
151             =head1 METHODS
152              
153             =head2 handle
154              
155             This is a class method - it receives the arguments, creates the controller
156             object and then uses it's L method.
157              
158             Should return a Plack::Response object, a string containing the HTML page, a code ref
159             or undef (which is later interpreted as 404).
160              
161             =head2 render
162              
163             Renders a template.
164              
165             =head2 local_dispatch
166              
167             Finds the method to be called for a given path and dispatches to it.
168              
169             =head2 req
170              
171             Plack::Reqest made from env
172              
173             =head2 template_search_path
174              
175             =head2 search_subcontrollers
176              
177             If search_subcontrollers returns true and there are no local actions
178             then subcontrollers are searched.
179              
180             =head2 dispatch_to_class
181              
182             =head2 DEBUG
183              
184             By default returns the DEBUG flag from the application. When this returns C then
185             some additional logging is directed to STDOUT.
186              
187             =head1 ATTRIBUTES
188              
189             =head2 url_map
190              
191             A hash that is used as path part to method map.
192              
193             =head2 app
194              
195             Links back to the application object.
196              
197             =head2 env
198              
199             L
200              
201             =head2 self_url
202              
203             =head2 path
204              
205             =head1 AUTHOR
206              
207             Zbigniew Lukasiak
208              
209             =head1 COPYRIGHT AND LICENSE
210              
211             This software is Copyright (c) 2010 by Zbigniew Lukasiak .
212              
213             This is free software, licensed under:
214              
215             The Artistic License 2.0 (GPL Compatible)
216              
217             =cut
218              
219              
220             __END__