File Coverage

blib/lib/Squatting/Controller.pm
Criterion Covered Total %
statement 6 26 23.0
branch 0 8 0.0
condition 2 7 28.5
subroutine 4 7 57.1
pod 5 5 100.0
total 17 53 32.0


line stmt bran cond sub pod time code
1             package Squatting::Controller;
2              
3             #use strict;
4             #no strict 'refs';
5             #use warnings;
6             #no warnings 'redefine';
7              
8             #our $AUTOLOAD;
9              
10             # constructor
11             sub new {
12 4     4 1 40 bless { name => $_[1], urls => $_[2], @_[3..$#_] } => $_[0];
13             }
14              
15             # (shallow) copy constructor
16             sub clone {
17 0     0 1 0 bless { %{$_[0]}, @_[1..$#_] } => ref($_[0]);
  0         0  
18             }
19              
20             # name - name of controller
21             # urls - arrayref of URL patterns that this controller responds to
22             # cr - Continuity::Request object
23             # env - incoming request headers and misc info like %ENV in the CGI days
24             # input - incoming CGI variables
25             # cookies - incoming *AND* outgoing cookies
26             # state - your session data
27             # v - outgoing vars
28             # status - outgoing HTTP Response status
29             # headers - outgoing HTTP headers
30             # view - name of default view
31             # log - logging object
32             # app - name of our app
33             for my $m (qw/name urls cr env input cookies state v status headers log view app/) {
34 4     4   35 *{$m} = sub : lvalue { $_[0]->{$m} }
35             }
36              
37             # HTTP methods
38             for my $m (qw/get post head put delete options trace connect/) {
39 1     1   476 *{$m} = sub { $_[0]->{$m}->(@_) }
40             }
41              
42             # For (sufficient) compatibility w/ the ubiquitous API that CGI.pm introduced
43             sub param {
44 0     0 1 0 my ($self, $k, @v) = @_;
45 0 0       0 if (defined $k) {
46 0 0       0 if (@v) {
47 0 0       0 $self->input->{$k} = ((@v > 1) ? \@v : $v[0]);
48             } else {
49 0         0 $self->input->{$k};
50             }
51             } else {
52 0         0 keys %{$self->input};
  0         0  
53             }
54             }
55              
56             # $content = $self->render($template, $view)
57             sub render {
58 0     0 1 0 my ($self, $template, $vn) = @_;
59 0         0 my $view;
60 0   0     0 $vn ||= $self->view;
61 0         0 my $app = $self->app;
62 0 0       0 if (defined($vn)) {
63 0         0 $view = ${$app."::Views::V"}{$vn}; # hash
  0         0  
64             } else { # vs
65 0         0 $view = ${$app."::Views::V"}[0]; # array -- Perl provides a lot of 'namespaces' so why not use them?
  0         0  
66             }
67 0         0 $view->headers = $self->headers;
68 0         0 $view->$template($self->v);
69             }
70              
71             # $self->redirect($url, $status_code)
72             sub redirect {
73 1     1 1 2399 my ($self, $l, $s) = @_;
74 1   50     9 $self->headers->{Location} = $l || '/';
75 1   50     14 $self->status = $s || 302;
76             }
77              
78             # default 404 controller
79             my $not_found = sub { $_[0]->status = 404; $_[0]->env->{REQUEST_PATH}." not found." };
80             our $r404 = Squatting::Controller->new(
81             R404 => [],
82             get => $not_found,
83             post => $not_found,
84             app => 'Squatting'
85             );
86              
87             1;
88              
89             =head1 NAME
90              
91             Squatting::Controller - default controller class for Squatting
92              
93             =head1 SYNOPSIS
94              
95             package App::Controllers;
96             use Squatting ':controllers';
97             our @C = (
98             C(
99             Thread => [ '/forum/(\d+)/thread/(\d+)-(\w+)' ],
100             get => sub {
101             my ($self, $forum_id, $thread_id, $slug) = @_;
102             #
103             # get thread from database...
104             #
105             $self->render('thread');
106             },
107             post => sub {
108             my ($self, $forum_id, $thread_id, $slug) = @_;
109             #
110             # add post to thread
111             #
112             $self->redirect(R('Thread', $forum_id, $thread_id, $slug));
113             }
114             )
115             );
116              
117             =head1 DESCRIPTION
118              
119             Squatting::Controller is the default controller class for Squatting
120             applications. Its job is to take HTTP requests and construct an appropriate
121             response by setting up output headers and returning content.
122              
123             =head1 API
124              
125             =head2 Object Construction
126              
127             =head3 Squatting::Controller->new($name => \@urls, %methods)
128              
129             The constructor takes a name, an arrayref or URL patterns, and a hash of
130             method definitions. There is a helper function called C() that makes this
131             slightly less verbose.
132              
133             =head3 $self->clone([ %opts ])
134              
135             This will create a shallow copy of the controller. You may optionally pass in
136             a hash of options that will be merged into the new clone.
137              
138             =head2 HTTP Request Handlers
139              
140             =head3 $self->get(@args)
141              
142             =head3 $self->post(@args)
143              
144             =head3 $self->put(@args)
145              
146             =head3 $self->delete(@args)
147              
148             =head3 $self->head(@args)
149              
150             =head3 $self->options(@args)
151              
152             =head3 $self->trace(@args)
153              
154             =head3 $self->connect(@args)
155              
156             These methods are called when their respective HTTP requests are sent to the
157             controller. @args is the list of regex captures from the URL pattern in
158             $self->urls that matched $self->env->{REQUEST_PATH}.
159              
160             =head2 Attribute Accessors
161              
162             The following methods are lvalue subroutines that contain information
163             relevant to the current controller and current request/response cycle.
164              
165             =head3 $self->name
166              
167             This returns the name of the controller.
168              
169             =head3 $self->urls
170              
171             This returns the arrayref of URL patterns that the controller responds to.
172              
173             =head3 $self->cr
174              
175             This returns the L object for the current session.
176              
177             =head3 $self->env
178              
179             This returns a hashref populated with a CGI-like environment. This is where
180             you'll find the incoming HTTP headers.
181              
182             =head3 $self->input
183              
184             This returns a hashref containing the incoming CGI parameters.
185              
186             B: Interpreting the query ?x=5&y=true&z=2&z=1&z=3 .
187              
188             $self->input->{x} is 5
189             $self->input->{y} is "true"
190             $self->input->{z} is [2, 1, 3]
191              
192             =head3 @keys = $self->param
193              
194             =head3 $value = $self->param($key)
195              
196             =head3 $self->param($key, $value)
197              
198             This is an accessor for C<$self-Einput> that provides an API that's a
199             subset of the L module's C function. It exists, because there
200             are many perl modules that can make use of an object that follows this API. It
201             is not complete, but it should be good enough for L
202             and many other modules.
203              
204             =head3 $self->cookies
205              
206             This returns a hashref that holds both the incoming and outgoing cookies.
207              
208             Incoming cookies are just simple scalar values, whereas outgoing cookies are
209             hashrefs that can be passed to L to construct a cookie string.
210              
211             B: Setting a cookie named 'foo'
212              
213             $self->cookies->{foo} = { -Value => 'bar', -Expires => '+1d' };
214              
215             B: Getting the value of a cookie named 'baz'
216              
217             my $baz = $self->cookies->{baz};
218              
219             =head3 $self->state
220              
221             If you've setup sessions, this method will return the current session
222             data as a hashref.
223              
224             =head3 $self->v
225              
226             This returns a hashref that represents the outgoing variables for this
227             request. This hashref will be passed to a view's templates when render()
228             is called.
229              
230             =head3 $self->status
231              
232             This returns an integer representing the outgoing HTTP status code.
233             See L for more details.
234              
235             $self->status = 404; # Resource Not Found
236              
237             =head3 $self->headers
238              
239             This returns a hashref representing the outgoing HTTP headers.
240              
241             B: Setting the outgoing Content-Type to text/plain
242              
243             $self->headers->{'Content-Type'} = 'text/plain';
244              
245             =head3 $self->log
246              
247             This returns a logging object if one has been set up for your app. If it
248             exists, you should be able to call methods like C, C,
249             C, C, and C against it, and the output of this would
250             typically end up in an error log.
251              
252             =head3 $self->view
253              
254             This returns the name of the default view for the current request. If
255             it's undefined, the first view in @App::Views::V will be considered the
256             default.
257              
258             =head3 $self->app
259              
260             This returns the name of the app that this controller belongs to.
261              
262             =head2 Output
263              
264             =head3 $self->render($template, [ $view ])
265              
266             This method will return a string generated by the specified template and view.
267             If a view is not specified, the first view object in @App::Views::V will be
268             used.
269              
270             =head3 $self->redirect($path, [ $status ])
271              
272             This method is a shortcut for setting $self->status to 302 and
273             $self->headers->{Location} to the specified URL. You may optionally pass in a
274             different status code as the second parameter.
275              
276             =head1 SEE ALSO
277              
278             L,
279             L
280              
281             =cut
282              
283             # Local Variables: ***
284             # mode: cperl ***
285             # indent-tabs-mode: nil ***
286             # cperl-close-paren-offset: -2 ***
287             # cperl-continued-statement-offset: 2 ***
288             # cperl-indent-level: 2 ***
289             # cperl-indent-parens-as-block: t ***
290             # cperl-tab-always-indent: nil ***
291             # End: ***
292             # vim:tabstop=8 softtabstop=2 shiftwidth=2 shiftround expandtab