line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
our $VERSION = '0.009'; |
3
|
|
|
|
|
|
|
our $DEFAULT_FACTORY = 'Catalyst::View::BasePerRequest::Factory'; |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
use Moose; |
6
|
1
|
|
|
1
|
|
1765620
|
use HTTP::Status (); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
6
|
|
7
|
1
|
|
|
1
|
|
5441
|
use Scalar::Util (); |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
12
|
|
8
|
1
|
|
|
1
|
|
4
|
use Module::Runtime (); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
21
|
|
9
|
1
|
|
|
1
|
|
12
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
560
|
|
10
|
|
|
|
|
|
|
extends 'Catalyst::View'; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
has 'catalyst_component_name' => (is=>'ro'); |
13
|
|
|
|
|
|
|
has 'app' => (is=>'ro', required=>1); |
14
|
|
|
|
|
|
|
has 'ctx' => (is=>'ro', required=>1); |
15
|
|
|
|
|
|
|
has 'root' => (is=>'rw', required=>1, default=>sub { shift }); |
16
|
|
|
|
|
|
|
has 'parent' => (is=>'rw', predicate=>'has_parent'); |
17
|
|
|
|
|
|
|
has 'content_type' => (is=>'ro', required=>0, predicate=>'has_content_type'); |
18
|
|
|
|
|
|
|
has 'code' => (is=>'rw', predicate=>'has_code'); |
19
|
|
|
|
|
|
|
has 'status_codes' => (is=>'rw', predicate=>'has_status_codes'); |
20
|
|
|
|
|
|
|
has 'injected_views' => (is=>'rw', predicate=>'has_injected_views'); |
21
|
|
|
|
|
|
|
has 'forwarded_args' => (is=>'rw', predicate=>'has_forwarded_args'); |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
|
24
|
0
|
|
|
0
|
0
|
0
|
my ($app, %views) = @_; |
25
|
|
|
|
|
|
|
$app->config->{views} = \%views; |
26
|
|
|
|
|
|
|
} |
27
|
0
|
|
|
0
|
0
|
0
|
|
28
|
0
|
|
|
|
|
0
|
my ($app, $method, @args) = @_; |
29
|
|
|
|
|
|
|
if(scalar(@args) > 1) { |
30
|
|
|
|
|
|
|
$app->config->{views}{$method} = \@args; |
31
|
|
|
|
|
|
|
} else { |
32
|
0
|
|
|
0
|
0
|
0
|
$app->config->{views}{$method} = $args[0]; |
33
|
0
|
0
|
|
|
|
0
|
} |
34
|
0
|
|
|
|
|
0
|
} |
35
|
|
|
|
|
|
|
|
36
|
0
|
|
|
|
|
0
|
my ($app, $ct) = @_; |
37
|
|
|
|
|
|
|
$app->config->{content_type} = $ct; |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
my $app = shift; |
41
|
0
|
|
|
0
|
0
|
0
|
my $codes = ref($_[0]) ? shift : [shift]; |
42
|
0
|
|
|
|
|
0
|
$app->config->{status_codes} = $codes; |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
my ($class, $app, $args) = @_; |
46
|
0
|
|
|
0
|
0
|
0
|
my $merged_args = $class->merge_config_hashes($class->config, $args); |
47
|
0
|
0
|
|
|
|
0
|
|
48
|
0
|
|
|
|
|
0
|
$merged_args = $class->modify_init_args($app, $merged_args) if $class->can('modify_init_args'); |
49
|
|
|
|
|
|
|
my %status_codes = $class->inject_http_status_helpers($merged_args); |
50
|
|
|
|
|
|
|
$merged_args->{status_codes} = \%status_codes if scalar(keys(%status_codes)); |
51
|
|
|
|
|
|
|
my @injected_views = $class->inject_view_helpers($merged_args); |
52
|
2
|
|
|
2
|
1
|
63007
|
$merged_args->{injected_views} = \@injected_views if scalar @injected_views; |
53
|
2
|
|
|
|
|
6
|
|
54
|
|
|
|
|
|
|
my $factory_class = Module::Runtime::use_module($class->factory_class($app, $merged_args)); |
55
|
2
|
50
|
|
|
|
193
|
return my $factory = $class->build_factory($factory_class, $app, $merged_args); |
56
|
2
|
|
|
|
|
8
|
} |
57
|
2
|
100
|
|
|
|
8
|
|
58
|
2
|
|
|
|
|
13
|
my ($class, $merged_args) = @_; |
59
|
2
|
50
|
|
|
|
4
|
if(my $views = $merged_args->{views}) { |
60
|
|
|
|
|
|
|
require Sub::Util; |
61
|
2
|
|
|
|
|
18
|
foreach my $method (keys %$views) { |
62
|
2
|
|
|
|
|
51
|
my ($view_name, @args_proto) = (); |
63
|
|
|
|
|
|
|
my $options_proto = $views->{$method}; |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
my $global_args_generator; |
66
|
2
|
|
|
2
|
0
|
5
|
if( (ref($options_proto)||'') eq 'ARRAY') { |
67
|
2
|
50
|
|
|
|
10
|
($view_name, @args_proto) = @$options_proto; |
68
|
0
|
|
|
|
|
0
|
$global_args_generator = (ref($args_proto[0])||'') eq 'CODE' ? |
69
|
0
|
|
|
|
|
0
|
shift(@args_proto) : |
70
|
0
|
|
|
|
|
0
|
sub { @args_proto }; |
71
|
0
|
|
|
|
|
0
|
} else { |
72
|
|
|
|
|
|
|
$view_name = $options_proto; |
73
|
0
|
|
|
|
|
0
|
} |
74
|
0
|
0
|
0
|
|
|
0
|
|
75
|
0
|
|
|
|
|
0
|
no strict 'refs'; |
76
|
|
|
|
|
|
|
*{"${class}::${method}"} = Sub::Util::set_subname "${class}::${method}" => sub { |
77
|
|
|
|
|
|
|
my ($self, @args) = @_; |
78
|
0
|
0
|
0
|
0
|
|
0
|
my @global_args = $global_args_generator ? $global_args_generator->($self, $self->ctx, @args) : (); |
|
0
|
|
|
|
|
0
|
|
79
|
|
|
|
|
|
|
my $view = $self->ctx->view($view_name, @global_args, @args); |
80
|
0
|
|
|
|
|
0
|
|
81
|
|
|
|
|
|
|
$view->root($self->root); |
82
|
|
|
|
|
|
|
$view->parent($self); |
83
|
1
|
|
|
1
|
|
7
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
1817
|
|
84
|
0
|
|
|
|
|
0
|
return $view; |
85
|
0
|
|
|
0
|
|
0
|
}; |
86
|
0
|
0
|
|
|
|
0
|
} |
87
|
0
|
|
|
|
|
0
|
return keys %$views; |
88
|
|
|
|
|
|
|
} |
89
|
0
|
|
|
|
|
0
|
return (); |
90
|
0
|
|
|
|
|
0
|
} |
91
|
|
|
|
|
|
|
|
92
|
0
|
|
|
|
|
0
|
my ($class, $merged_args) = @_; |
93
|
0
|
|
|
|
|
0
|
|
94
|
|
|
|
|
|
|
my %status_codes = (); |
95
|
0
|
|
|
|
|
0
|
if(exists $merged_args->{status_codes}) { |
96
|
|
|
|
|
|
|
%status_codes = map { $_=>1 } @{$merged_args->{status_codes}}; |
97
|
2
|
|
|
|
|
7
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
foreach my $helper( grep { $_=~/^http/i} @HTTP::Status::EXPORT_OK) { |
100
|
|
|
|
|
|
|
my $subname = lc $helper; |
101
|
2
|
|
|
2
|
0
|
5
|
my $code = HTTP::Status->$helper; |
102
|
|
|
|
|
|
|
if(scalar(keys(%status_codes))) { |
103
|
2
|
|
|
|
|
4
|
next unless $status_codes{$code}; |
104
|
2
|
100
|
|
|
|
5
|
} |
105
|
1
|
|
|
|
|
2
|
eval "sub ${\$class}::${\$subname} { return shift->respond(HTTP::Status::$helper,\\\@_) }"; |
|
3
|
|
|
|
|
10
|
|
|
1
|
|
|
|
|
3
|
|
106
|
|
|
|
|
|
|
eval "sub ${\$class}::set_${\$subname} { |
107
|
|
|
|
|
|
|
my (\$self, \@headers) = \@_; |
108
|
2
|
|
|
|
|
4
|
\$self->ctx->res->status(HTTP::Status::$helper); |
|
144
|
|
|
|
|
254
|
|
109
|
138
|
|
|
|
|
319
|
\$self->ctx->res->headers->push_header(\@headers) if \@headers; |
110
|
138
|
|
|
|
|
387
|
return \$self; |
111
|
138
|
100
|
|
|
|
262
|
}"; |
112
|
69
|
100
|
|
|
|
133
|
} |
113
|
|
|
|
|
|
|
|
114
|
72
|
|
|
0
|
0
|
85
|
return %status_codes; |
|
72
|
|
|
0
|
0
|
157
|
|
|
72
|
|
|
0
|
0
|
3079
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
1
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
1
|
|
|
0
|
0
|
468
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
1
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
1
|
|
|
0
|
0
|
503
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
115
|
72
|
0
|
|
0
|
0
|
182
|
} |
|
72
|
0
|
|
0
|
0
|
157
|
|
|
72
|
0
|
|
0
|
0
|
5138
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
50
|
|
1
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
1
|
0
|
|
0
|
0
|
495
|
|
|
1
|
0
|
|
0
|
0
|
29
|
|
|
1
|
0
|
|
0
|
0
|
179
|
|
|
1
|
0
|
|
0
|
0
|
204
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
50
|
|
1
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
0
|
|
0
|
0
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
527
|
|
|
1
|
|
|
|
|
27
|
|
|
1
|
|
|
|
|
135
|
|
|
1
|
|
|
|
|
3
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
my ($class, $app, $merged_args) = @_; |
118
|
|
|
|
|
|
|
return $DEFAULT_FACTORY; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
my ($class, %args) = @_; |
122
|
|
|
|
|
|
|
return $class->new(%args); |
123
|
2
|
|
|
|
|
10
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
my ($class, $factory_class, $app, $merged_args) = @_; |
126
|
|
|
|
|
|
|
return my $factory = bless +{ |
127
|
2
|
|
|
2
|
0
|
4
|
class=>$class, |
128
|
2
|
|
|
|
|
8
|
app=>$app, |
129
|
|
|
|
|
|
|
merged_args=>$merged_args, |
130
|
|
|
|
|
|
|
}, $factory_class; |
131
|
|
|
|
|
|
|
} |
132
|
12
|
|
|
12
|
1
|
46
|
|
133
|
12
|
|
|
|
|
338
|
my ($self, $ctx, @args) = @_; |
134
|
|
|
|
|
|
|
die "You need to write a 'render' method!"; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
2
|
|
|
2
|
0
|
6
|
my ($self, $c, @args) = @_; |
138
|
2
|
|
|
|
|
13
|
$self->forwarded_args(\@args); |
139
|
|
|
|
|
|
|
return $self->respond(); |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
my ($self, $status, $headers, @args) = @_; |
143
|
|
|
|
|
|
|
for my $r ($self->ctx->res) { |
144
|
|
|
|
|
|
|
$r->status($status) if $status && $r->status; # != 200; # Catalyst sets 200 |
145
|
|
|
|
|
|
|
|
146
|
0
|
|
|
0
|
0
|
0
|
Module::Runtime::use_module('Catalyst::View::BasePerRequest::Exception::InvalidStatusCode')->throw(status_code=>$r->status) |
147
|
0
|
|
|
|
|
0
|
if $self->has_status_codes && !$self->status_codes->{$r->status}; |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
$r->content_type($self->content_type) if !$r->content_type && $self->has_content_type; |
150
|
|
|
|
|
|
|
$r->headers->push_header(@{$headers}) if $headers; |
151
|
1
|
|
|
1
|
1
|
183
|
$r->body($self->get_rendered(@args)); |
152
|
1
|
|
|
|
|
32
|
} |
153
|
1
|
|
|
|
|
5
|
return $self; # allow chaining |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
my $self = shift; |
157
|
3
|
|
|
3
|
1
|
8
|
my @rendered = (); |
158
|
3
|
|
|
|
|
79
|
|
159
|
3
|
100
|
66
|
|
|
134
|
eval { |
160
|
|
|
|
|
|
|
my @args = $self->prepare_render_args(@_); |
161
|
|
|
|
|
|
|
@rendered = map { |
162
|
3
|
50
|
33
|
|
|
440
|
Scalar::Util::blessed($_) && $_->can('get_rendered') ? $_->get_rendered : $_; |
163
|
|
|
|
|
|
|
} $self->render(@args); |
164
|
3
|
50
|
33
|
|
|
294
|
1; |
165
|
3
|
100
|
|
|
|
485
|
} || do { |
|
2
|
|
|
|
|
160
|
|
166
|
3
|
|
|
|
|
43
|
$self->do_handle_render_exception($@); |
167
|
|
|
|
|
|
|
}; |
168
|
3
|
|
|
|
|
31
|
|
169
|
|
|
|
|
|
|
return $self->flatten_rendered_for_response_body(@rendered); |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
12
|
|
|
12
|
0
|
1073
|
|
173
|
12
|
|
|
|
|
20
|
|
174
|
|
|
|
|
|
|
my ($self, $err) = @_; |
175
|
|
|
|
|
|
|
return $err->rethrow if Scalar::Util::blessed($err) && $err->can('rethrow'); |
176
|
12
|
|
|
|
|
31
|
my $class = Module::Runtime::use_module($self->render_error_class); |
177
|
|
|
|
|
|
|
$class->throw(render_error=>$err); |
178
|
12
|
100
|
66
|
|
|
51
|
} |
|
12
|
|
|
|
|
402
|
|
179
|
|
|
|
|
|
|
|
180
|
12
|
|
|
|
|
31
|
my ($self, @args) = @_; |
181
|
12
|
50
|
|
|
|
21
|
|
182
|
0
|
|
|
|
|
0
|
if($self->has_code) { |
183
|
|
|
|
|
|
|
my $inner = $self->render_code; |
184
|
|
|
|
|
|
|
unshift @args, $inner; # pass any $inner as an argument to ->render() |
185
|
12
|
|
|
|
|
33
|
} |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
return ($self->ctx, @args); |
188
|
12
|
|
|
12
|
0
|
26
|
} |
189
|
|
|
|
|
|
|
|
190
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
191
|
|
|
|
|
|
|
my @inner = map { |
192
|
|
|
|
|
|
|
Scalar::Util::blessed($_) && $_->can('get_rendered') ? $_->get_rendered : $_; |
193
|
0
|
|
|
0
|
0
|
0
|
} $self->execute_code_callback($self->prepare_render_code_args); |
194
|
0
|
0
|
0
|
|
|
0
|
|
195
|
0
|
|
|
|
|
0
|
my $flat = $self->flatten_rendered_for_inner_content(@inner); |
196
|
0
|
|
|
|
|
0
|
return $flat; |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
my ($self, @args) = @_; |
200
|
12
|
|
|
12
|
0
|
22
|
return $self->code->(@args); |
201
|
|
|
|
|
|
|
} |
202
|
12
|
100
|
|
|
|
383
|
|
203
|
6
|
|
|
|
|
17
|
my ($self) = @_; |
204
|
6
|
|
|
|
|
15
|
return $self; |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
12
|
|
|
|
|
315
|
|
208
|
|
|
|
|
|
|
my $self = shift; |
209
|
|
|
|
|
|
|
return join '', grep { defined($_) } @_; |
210
|
|
|
|
|
|
|
} |
211
|
6
|
|
|
6
|
0
|
14
|
|
212
|
|
|
|
|
|
|
my ($self, $name, $options) = @_; |
213
|
6
|
50
|
33
|
|
|
27
|
my %options = $options ? %$options : (); |
|
6
|
|
|
|
|
250
|
|
214
|
|
|
|
|
|
|
my $default = exists($options{default}) ? $options{default} : ''; |
215
|
|
|
|
|
|
|
|
216
|
6
|
|
|
|
|
21
|
return exists($self->ctx->stash->{view_blocks}{$name}) ? |
217
|
6
|
|
|
|
|
14
|
$self->ctx->stash->{view_blocks}{$name} : |
218
|
|
|
|
|
|
|
$default; |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
6
|
|
|
6
|
0
|
16
|
my $self = shift; |
222
|
6
|
|
|
|
|
163
|
if((ref($_[0])||'') eq 'CODE') { |
223
|
|
|
|
|
|
|
return $self->flatten_rendered_for_content_blocks($_[0]->($_[1])); |
224
|
|
|
|
|
|
|
} else { |
225
|
|
|
|
|
|
|
return $self->flatten_rendered_for_content_blocks(@_); |
226
|
6
|
|
|
6
|
0
|
15
|
} |
227
|
6
|
|
|
|
|
16
|
} |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
|
230
|
6
|
|
|
6
|
0
|
16
|
my ($self, $name, $value) = @_; |
231
|
|
|
|
|
|
|
Module::Runtime::use_module($self->_content_exception_class) |
232
|
|
|
|
|
|
|
->throw(content_name=>$name, content_msg=>'Content block is already defined') if $self->_content_exists($name); |
233
|
42
|
|
|
42
|
0
|
52
|
$self->ctx->stash->{view_blocks}{$name} = $self->render_content_value($value); |
234
|
42
|
|
|
|
|
65
|
return; |
|
42
|
|
|
|
|
744
|
|
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
my ($self, $name, $value) = @_; |
238
|
12
|
|
|
12
|
1
|
957
|
Module::Runtime::use_module($self->_content_exception_class) |
239
|
12
|
100
|
|
|
|
33
|
->throw(content_name=>$name, content_msg=>'Content block doesnt exist for appending') unless $self->_content_exists($name); |
240
|
12
|
100
|
|
|
|
27
|
$self->ctx->stash->{view_blocks}{$name} .= $self->render_content_value($value); |
241
|
|
|
|
|
|
|
return; |
242
|
|
|
|
|
|
|
} |
243
|
12
|
100
|
|
|
|
312
|
|
244
|
|
|
|
|
|
|
my ($self, $name, $value) = @_; |
245
|
|
|
|
|
|
|
Module::Runtime::use_module($self->_content_exception_class) |
246
|
|
|
|
|
|
|
->throw(content_name=>$name, content_msg=>'Content block doesnt exist for prepending') unless $self->_content_exists($name); |
247
|
|
|
|
|
|
|
$self->ctx->stash->{view_blocks}{$name} = $self->render_content_value($value) . $self->ctx->stash->{view_blocks}{$name}; |
248
|
24
|
|
|
24
|
0
|
650
|
return; |
249
|
24
|
100
|
100
|
|
|
76
|
} |
250
|
6
|
|
|
|
|
16
|
|
251
|
|
|
|
|
|
|
|
252
|
18
|
|
|
|
|
77
|
my ($self, $name, $value) = @_; |
253
|
|
|
|
|
|
|
Module::Runtime::use_module($self->_content_exception_class) |
254
|
|
|
|
|
|
|
->throw(content_name=>$name, content_msg=>'Content block doesnt exist for replacing') unless $self->_content_exists($name); |
255
|
|
|
|
|
|
|
$self->ctx->stash->{view_blocks}{$name} = $self->render_content_value($value); |
256
|
24
|
|
|
24
|
0
|
73
|
return; |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
6
|
|
|
6
|
1
|
49
|
my ($self, $name, $value) = @_; |
260
|
6
|
50
|
|
|
|
16
|
Module::Runtime::use_module($self->_content_exception_class) |
261
|
|
|
|
|
|
|
->throw(content_name=>$name, content_msg=>'Content block doesnt exist') unless $self->_content_exists($name); |
262
|
6
|
|
|
|
|
353
|
$self->ctx->stash->{view_blocks}{$name} = $self->render_content_value($value, $self->ctx->stash->{view_blocks}{$name}); |
263
|
6
|
|
|
|
|
322
|
return; |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
|
267
|
6
|
|
|
6
|
1
|
32
|
my ($self, $name) = @_; |
268
|
6
|
50
|
|
|
|
13
|
return exists $self->ctx->stash->{view_blocks}{$name} ? 1:0; |
269
|
|
|
|
|
|
|
} |
270
|
6
|
|
|
|
|
460
|
|
271
|
6
|
|
|
|
|
14
|
|
272
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=head1 NAME |
275
|
6
|
|
|
6
|
0
|
77
|
|
276
|
6
|
50
|
|
|
|
13
|
Catalyst::View::Template::BasePerRequest - Catalyst base view for per request, strongly typed templates |
277
|
|
|
|
|
|
|
|
278
|
6
|
|
|
|
|
331
|
=head1 SYNOPSIS |
279
|
6
|
|
|
|
|
324
|
|
280
|
|
|
|
|
|
|
package Example::View::Hello; |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
use Moose; |
283
|
|
|
|
|
|
|
|
284
|
0
|
|
|
0
|
1
|
0
|
extends 'Catalyst::View::BasePerRequest'; |
285
|
0
|
0
|
|
|
|
0
|
|
286
|
|
|
|
|
|
|
has name => (is=>'ro', required=>1); |
287
|
0
|
|
|
|
|
0
|
has age => (is=>'ro', required=>1); |
288
|
0
|
|
|
|
|
0
|
|
289
|
|
|
|
|
|
|
sub render { |
290
|
|
|
|
|
|
|
my ($self, $c) = @_; |
291
|
|
|
|
|
|
|
return "<div>Hello @{[ $self->name] }", |
292
|
6
|
|
|
6
|
1
|
55
|
"I see you are @{[ $self->age]} years old!</div>"; |
293
|
6
|
50
|
|
|
|
14
|
} |
294
|
|
|
|
|
|
|
|
295
|
6
|
|
|
|
|
471
|
__PACKAGE__->config( |
296
|
6
|
|
|
|
|
311
|
content_type=>'text/html', |
297
|
|
|
|
|
|
|
status_codes=>[200] |
298
|
|
|
|
|
|
|
); |
299
|
0
|
|
|
0
|
|
0
|
|
300
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable(); |
301
|
|
|
|
|
|
|
|
302
|
24
|
|
|
24
|
|
37
|
One way to use it in a controller: |
303
|
24
|
100
|
|
|
|
636
|
|
304
|
|
|
|
|
|
|
package Example::Controller::Root; |
305
|
|
|
|
|
|
|
|
306
|
0
|
|
|
0
|
1
|
|
use Moose; |
307
|
|
|
|
|
|
|
use MooseX::MethodAttributes; |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
extends 'Catalyst::Controller'; |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
sub root :Chained(/) PathPart('') CaptureArgs(0) { } |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
sub hello :Chained(root) Args(0) { |
314
|
|
|
|
|
|
|
my ($self, $c) = @_; |
315
|
|
|
|
|
|
|
return $c->view(Hello => |
316
|
|
|
|
|
|
|
name => 'John', |
317
|
|
|
|
|
|
|
age => 53 |
318
|
|
|
|
|
|
|
)->http_ok; |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
__PACKAGE__->config(namespace=>''); |
322
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=head1 DESCRIPTION |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
B<NOTE>: This is early access code. Although it's based on several other internal projects |
327
|
|
|
|
|
|
|
which I have iterated over this concept for a number of years I still reserve the right |
328
|
|
|
|
|
|
|
to make breaking changes as needed. |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
B<NOTE>: You probably won't actually use this directly, it's intended to be a base framework |
331
|
|
|
|
|
|
|
for building / prototyping strongly typed / per request views in L<Catalyst>. This |
332
|
|
|
|
|
|
|
documentation serves as an overview of the concept. In particular please note that |
333
|
|
|
|
|
|
|
this code does not address any issues around HTML / Javascript injection attacks or |
334
|
|
|
|
|
|
|
provides any auto escaping. You'll need to bake those features into whatever you |
335
|
|
|
|
|
|
|
build on top of this. Because of this the following documentation is light and is mostly |
336
|
|
|
|
|
|
|
intended to help anyone who is planning to build something on top of this framework |
337
|
|
|
|
|
|
|
rather than use it directly. |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
B<NOTE>: This distribution's C</example> directory gives you a toy prototype using L<HTML::Tags> |
340
|
|
|
|
|
|
|
as the basis to a view as well as some raw examples using this code directly (again, |
341
|
|
|
|
|
|
|
not recommended for anything other than learning). |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
In a classic L<Catalyst> application with server side templates, the canonical approach |
344
|
|
|
|
|
|
|
is to use a 'view' as a sort of handler for an underlying template system (such as |
345
|
|
|
|
|
|
|
L<Template::Toolkit> or L<Xslate>) and to send data to this template by populating |
346
|
|
|
|
|
|
|
the stash. These views are very lean, and in general don't provide much in the way |
347
|
|
|
|
|
|
|
of view logic processing; they generally are just a thin proxy for the underlying |
348
|
|
|
|
|
|
|
templating system. |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
This approach has the upside of being very simple to understand and in general works |
351
|
|
|
|
|
|
|
ok with a simple websites. There are however downsides as your site becomes more |
352
|
|
|
|
|
|
|
complex. First of all the stash as a means to pass data from the Controller to the |
353
|
|
|
|
|
|
|
template can be fragile. For example just making a simple typo in the stash key |
354
|
|
|
|
|
|
|
can break your templates in ways that might not be easy to figure out. Also your |
355
|
|
|
|
|
|
|
template can't enforce its requirements very easily (and it's not easy for someone |
356
|
|
|
|
|
|
|
working in the controller to know exactly what things need to go into the stash in |
357
|
|
|
|
|
|
|
order for the template to function as desired.) The view itself has no way of |
358
|
|
|
|
|
|
|
providing view / display oriented logic; generally that logic ends up creeping back up |
359
|
|
|
|
|
|
|
into the controller in ways that break the notion of MVC's separation of concerns. |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
Lastly the controller doesn't have a defined API with the view. All it can ask the view |
362
|
|
|
|
|
|
|
is 'go ahead and process yourself using the current context' and all it gets back from |
363
|
|
|
|
|
|
|
the view is a string response. If the controller wishes to introspect this response |
364
|
|
|
|
|
|
|
or modify it in some way prior to it being sent back to the client, you have few options |
365
|
|
|
|
|
|
|
apart from using regular expression matching to try and extract the required information |
366
|
|
|
|
|
|
|
or to modify the response string. |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
Basically the classic approach works acceptable well for a simple website but starts to |
369
|
|
|
|
|
|
|
break down as your site becomes more complicated. |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
An alternative approach, which is explored in this distribution, is to have a defined view for |
372
|
|
|
|
|
|
|
each desired response and for it to define an explicit API that the controller uses to provide the required |
373
|
|
|
|
|
|
|
and optional data to the view. This defined view can further define its own methods |
374
|
|
|
|
|
|
|
used to generate suitable information for display. Such an approach is more initial work |
375
|
|
|
|
|
|
|
as well as learning for the website developers, but in the long term it can provide |
376
|
|
|
|
|
|
|
an easier path to sustainable development and maintainence with hopefully fewer bugs |
377
|
|
|
|
|
|
|
and overall site issues. |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
=head1 EXAMPLE: Basic |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
The most minimal thing your view must provide in a C<render> method. This method gets |
382
|
|
|
|
|
|
|
the view object and the context (it can also receive additional arguments if this view is |
383
|
|
|
|
|
|
|
being called from other views as a wrapper or parent view; more on that later). |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
The C<render> method should return a string or array of strings suitable for the body of |
386
|
|
|
|
|
|
|
the response> B<NOTE> if you return an array of strings we flatten the array into a single |
387
|
|
|
|
|
|
|
string since the C<body> method of L<Catalyst::Response> can't take an array. |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
Here's a minimal example: |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
package Example::View::Hello; |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
use Moose; |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
extends 'Catalyst::View::BasePerRequest'; |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
sub render { |
398
|
|
|
|
|
|
|
my ($self, $c) = @_; |
399
|
|
|
|
|
|
|
return "<p>Hello</p>"; |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
__PACKAGE__->config(content_type=>'text/html'); |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
And here's an example view with attributes: |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
package Example::View::HelloPerson; |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
use Moose; |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
extends 'Catalyst::View::BasePerRequest'; |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
has name => (is=>'ro', required=>1); |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
sub render { |
415
|
|
|
|
|
|
|
my ($self, $c) = @_; |
416
|
|
|
|
|
|
|
return qq[ |
417
|
|
|
|
|
|
|
<div> |
418
|
|
|
|
|
|
|
Hello @{[ $self->name ]} |
419
|
|
|
|
|
|
|
</div>]; |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable(); |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
One way to invoke this view from the controller using the traditional C<forward> method: |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
package Example::Controller::Root; |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
use Moose; |
429
|
|
|
|
|
|
|
use MooseX::MethodAttributes; |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
extends 'Catalyst::Controller'; |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
sub root :Chained(/) PathPart('') CaptureArgs(0) { } |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
sub hello :Chained(root) Args(0) { |
436
|
|
|
|
|
|
|
my ($self, $c) = @_; |
437
|
|
|
|
|
|
|
my $view = $c->view(HelloPerson => (name => 'John')); |
438
|
|
|
|
|
|
|
return $c->forward($view); |
439
|
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
__PACKAGE__->config(namespace=>''); |
442
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
Alternatively using L</"RESPONSE HELPERS">: |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
package Example::Controller::Root; |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
use Moose; |
449
|
|
|
|
|
|
|
use MooseX::MethodAttributes; |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
extends 'Catalyst::Controller'; |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
sub root :Chained(/) PathPart('') CaptureArgs(0) { } |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
sub hello :Chained(root) Args(0) { |
456
|
|
|
|
|
|
|
my ($self, $c) = @_; |
457
|
|
|
|
|
|
|
return $c->view(HelloPerson => (name => 'John'))->http_ok; |
458
|
|
|
|
|
|
|
} |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
__PACKAGE__->config(namespace=>''); |
461
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
The following Moose attributes are considered part of this classes public API |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
=head2 app |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
The string namespace of your L<Catalyst> application. |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
=head2 ctx |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
The current L<Catalyst> context |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
=head2 root |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
The root view object (that is the top view that was called first, usually from |
478
|
|
|
|
|
|
|
the controller). |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
=head2 parent |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
=head2 has_parent |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
If the view was called from another view, that first view is set as the parent. |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
=head2 injected_views |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
=head2 has_injected_views |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
An arrayref of the method names associated with any injected views. |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
=head1 METHODS |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
The following methods are considered part of this classes public API |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
=head2 process |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
Renders a view and sets up the response object. Generally this is called from a |
499
|
|
|
|
|
|
|
controller via the C<forward> method and not directly: |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
$c->forward($view); |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
=head2 respond |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
Accepts an HTTP status code and an arrayref of key / values used to set HTTP headers for a |
506
|
|
|
|
|
|
|
response. Example: |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
$view->respond(201, [ location=>$url ]); |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
Returns the view object to make it easier to do method chaining |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
=head2 detach |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
Just a shortcut to ->detach via the context |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
=head1 CONTENT BLOCK HELPERS |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
Content block helpers are an optional feature to make it easy to create and populate content |
519
|
|
|
|
|
|
|
areas between different views. Although you can also do this with object attributes you may |
520
|
|
|
|
|
|
|
wish to separate template / text from data. Example: |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
package Example::View::Layout; |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
use Moose; |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
extends 'Catalyst::View::BasePerRequest'; |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
has title => (is=>'ro', required=>1, default=>'Missing Title'); |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
sub render { |
531
|
|
|
|
|
|
|
my ($self, $c, $inner) = @_; |
532
|
|
|
|
|
|
|
return " |
533
|
|
|
|
|
|
|
<html> |
534
|
|
|
|
|
|
|
<head> |
535
|
|
|
|
|
|
|
<title>@{[ $self->title ]}</title> |
536
|
|
|
|
|
|
|
@{[ $self->content('css') ]} |
537
|
|
|
|
|
|
|
</head> |
538
|
|
|
|
|
|
|
<body>$inner</body> |
539
|
|
|
|
|
|
|
</html>"; |
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
__PACKAGE__->config(content_type=>'text/html'); |
543
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable(); |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
package Example::View::Hello; |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
use Moose; |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
extends 'Catalyst::View::BasePerRequest'; |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
has name => (is=>'ro', required=>1); |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
sub render { |
554
|
|
|
|
|
|
|
my ($self, $c) = @_; |
555
|
|
|
|
|
|
|
return $c->view(Layout => title=>'Hello', sub { |
556
|
|
|
|
|
|
|
my $layout = shift; |
557
|
|
|
|
|
|
|
$self->content_for('css', "<style>...</style>"); |
558
|
|
|
|
|
|
|
return "<div>Hello @{[ $self->name ]}!</div>"; |
559
|
|
|
|
|
|
|
}); |
560
|
|
|
|
|
|
|
} |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
__PACKAGE__->config(content_type=>'text/html', status_codes=>[200]); |
563
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable(); |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
=head2 content |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
Examples: |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
$self->content($name); |
570
|
|
|
|
|
|
|
$self->content($name, +{ default=>'No main content' }); |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
Gets a content block string by '$name'. If the block has not been defined returns either |
573
|
|
|
|
|
|
|
a zero length string or whatever you set the default key of the hashref options to. |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
=head2 content_for |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
Sets a named content block or throws an exception if the content block already exists. |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
=head2 content_append |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
Appends to a named content block or throws an exception if the content block doesn't exist. |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
=head2 content_replace |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
Replaces a named content block or throws an exception if the content block doesn't exist. |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
=head2 content_around |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
Wraps an existing content with new content. Throws an exception if the named content block doesn't exist. |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
$self->content_around('footer', sub { |
592
|
|
|
|
|
|
|
my $footer = shift; |
593
|
|
|
|
|
|
|
return "wrapped $footer end wrap"; |
594
|
|
|
|
|
|
|
}); |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
=head1 VIEW INJECTION |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
Usually when building a website of more than toy complexity you will find that you will |
599
|
|
|
|
|
|
|
decompose your site into sub views and view wrappers. Although you can call the C<view> |
600
|
|
|
|
|
|
|
method on the context, I think its more in the spirit of the idea of a strong or structured |
601
|
|
|
|
|
|
|
view to have a view declare upfront what views its calling as sub views. That lets you |
602
|
|
|
|
|
|
|
have more central control over view initalization and decouples how you are calling your |
603
|
|
|
|
|
|
|
views from the actual underlying views. It can also tidy up some of the code and lastly |
604
|
|
|
|
|
|
|
makes it easy to immediately know what views are needed for the current one. This can |
605
|
|
|
|
|
|
|
help with later refactoring (I've worked on projects where sub views got detached from |
606
|
|
|
|
|
|
|
actual use but nobody ever cleaned them up.) |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
To inject a view into the current one, you need to declare it in configuration: |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
__PACKAGE__->config( |
611
|
|
|
|
|
|
|
content_type=>'text/html', |
612
|
|
|
|
|
|
|
status_codes=>[200,404,400], |
613
|
|
|
|
|
|
|
views=>+{ |
614
|
|
|
|
|
|
|
layout1 => [ Layout => sub { my ($self, $c) = @_; return title=>'Hey!' } ], |
615
|
|
|
|
|
|
|
layout2 => [ Layout => (title=>'Yeah!') ], |
616
|
|
|
|
|
|
|
layout3 => 'Layout', |
617
|
|
|
|
|
|
|
}, |
618
|
|
|
|
|
|
|
); |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
Basically this is a hashref under the C<views> key, where each key in the hashref is the name |
621
|
|
|
|
|
|
|
of the method you are injecting into the current view which is responsible for creating the |
622
|
|
|
|
|
|
|
sub view and the value is one of three options: |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
=over |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
=item A scalar value |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
__PACKAGE__->config( |
629
|
|
|
|
|
|
|
content_type=>'text/html', |
630
|
|
|
|
|
|
|
status_codes=>[200,404,400], |
631
|
|
|
|
|
|
|
views=>+{ |
632
|
|
|
|
|
|
|
layout => 'Layout', |
633
|
|
|
|
|
|
|
}, |
634
|
|
|
|
|
|
|
); |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
This is the simplest option, it just injects a method that will call the named view and pass |
637
|
|
|
|
|
|
|
any arguments from the method but does not add any global arguments. |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
=item An arrayref |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
__PACKAGE__->config( |
642
|
|
|
|
|
|
|
content_type=>'text/html', |
643
|
|
|
|
|
|
|
status_codes=>[200,404,400], |
644
|
|
|
|
|
|
|
views=>+{ |
645
|
|
|
|
|
|
|
layout => [ Layout => (title=>'Yeah!') ], |
646
|
|
|
|
|
|
|
}, |
647
|
|
|
|
|
|
|
); |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
This option allows you to set some argument defaults to the view called. The first item in the |
650
|
|
|
|
|
|
|
arrayref must be the real name of the view, followed by arguments which are merged with any provided |
651
|
|
|
|
|
|
|
to the method. |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
=item A coderef |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
__PACKAGE__->config( |
656
|
|
|
|
|
|
|
content_type=>'text/html', |
657
|
|
|
|
|
|
|
status_codes=>[200,404,400], |
658
|
|
|
|
|
|
|
views=>+{ |
659
|
|
|
|
|
|
|
layout => [ Layout => sub { my ($self, $c) = @_; return title=>'Hey!' } ], |
660
|
|
|
|
|
|
|
}, |
661
|
|
|
|
|
|
|
); |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
The most complex option, you should probably reserve for very special needs. Basically this coderef |
664
|
|
|
|
|
|
|
will be called with the current view instance and Catalyst context; it should return arguments which |
665
|
|
|
|
|
|
|
with then be merged and treated as in the arrayref option. |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
=back |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
Now you can call for the sub view via a simple method call on the view, rather than via the context: |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
package Example::View::Hello; |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
use Moose; |
674
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
extends 'Catalyst::View::BasePerRequest'; |
676
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
has name => (is=>'ro', required=>1); |
678
|
|
|
|
|
|
|
has age => (is=>'ro', required=>1); |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
sub render { |
682
|
|
|
|
|
|
|
my ($self, $c) = @_; |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
return $self->layout(title=>'Hello!', sub { |
685
|
|
|
|
|
|
|
my $layout = shift; |
686
|
|
|
|
|
|
|
return "Hello @{[$self->name]}; you are @{[$self->age]} years old!"; |
687
|
|
|
|
|
|
|
}); |
688
|
|
|
|
|
|
|
} |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
__PACKAGE__->config( |
692
|
|
|
|
|
|
|
content_type=>'text/html', |
693
|
|
|
|
|
|
|
status_codes=>[200,404,400], |
694
|
|
|
|
|
|
|
views=>+{ |
695
|
|
|
|
|
|
|
layout => 'Layout', |
696
|
|
|
|
|
|
|
}, |
697
|
|
|
|
|
|
|
); |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
=head1 RESPONSE HELPERS |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
When you create a view instance the actual response is not send to the client until |
705
|
|
|
|
|
|
|
the L</respond> method is called (either directly, via L</process> or thru the generated |
706
|
|
|
|
|
|
|
response helpers). |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
Response helpers are just methods that call L</respond> with the correct status code |
709
|
|
|
|
|
|
|
and using a more easy to remember name (and possibly a more self documenting one). |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
For example: |
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
$c->view('Login')->http_ok; |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
calls the L</respond> method with the expected http status code. You can also pass |
716
|
|
|
|
|
|
|
arguments to the response helper which are send to L</respond> and used to add HTTP |
717
|
|
|
|
|
|
|
headers to the response. |
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
$c->view("NewUser") |
720
|
|
|
|
|
|
|
->http_created(location=>$url); |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
Please note that calling a response helper only sets up the response object, it doesn't |
723
|
|
|
|
|
|
|
stop any future actions in you controller. If you really want to stop action processing |
724
|
|
|
|
|
|
|
you'll need to call L</detach>: |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
return $c->view("Error") |
727
|
|
|
|
|
|
|
->http_bad_request |
728
|
|
|
|
|
|
|
->detach; |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
If you don't want to generate the response yet (perhaps you'll leave that to a global 'end' |
731
|
|
|
|
|
|
|
action) you can use the 'set_http_$STATUS' helpers instead which wil just set the response |
732
|
|
|
|
|
|
|
status. |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
return $c->view("Error") |
735
|
|
|
|
|
|
|
->set_http_bad_request |
736
|
|
|
|
|
|
|
->detach; |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
Response helpers are just lowercased names you'll find for the codes listed in L<HTTP::Status>. |
739
|
|
|
|
|
|
|
Some of the most common ones I find in my code: |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
http_ok |
742
|
|
|
|
|
|
|
http_created |
743
|
|
|
|
|
|
|
http_bad_request |
744
|
|
|
|
|
|
|
http_unauthorized |
745
|
|
|
|
|
|
|
http_not_found |
746
|
|
|
|
|
|
|
http_internal_server_error |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
By default we create response helpers for all the status codes in L<HTTP::Status>. However |
749
|
|
|
|
|
|
|
if you set the C<status_codes> configuration key (see L</status_codes>) you can limit the |
750
|
|
|
|
|
|
|
generated helpers to specific codes. This can be useful since most views are only meaningful |
751
|
|
|
|
|
|
|
with a limited set of response codes. |
752
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
=head1 RUNTIME HOOKS |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
This class defines the following method hooks you may optionally defined in your |
756
|
|
|
|
|
|
|
view subclass in order to control or otherwise influence how the view works. |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
=head2 $class->modify_init_args($app, $args) |
759
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
Runs when C<COMPONENT> is called during C<setup_components>. This gets a reference |
761
|
|
|
|
|
|
|
to the merged arguments from all configuration. You should return this reference |
762
|
|
|
|
|
|
|
after modification. |
763
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
This is for modifying or adding arguments that are application scoped rather than context |
765
|
|
|
|
|
|
|
scoped. |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
=head2 prepare_build_args |
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
This method will be called (if defined) by the factory class during build time. It can be used |
770
|
|
|
|
|
|
|
to inject args and modify args. It gets the context and C<@args> as arguments and should return |
771
|
|
|
|
|
|
|
all the arguments you want to pass to C<new>. Example: |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
sub prepare_build_args { |
774
|
|
|
|
|
|
|
my ($class, $c, @args) = @_; |
775
|
|
|
|
|
|
|
# Mess with @args |
776
|
|
|
|
|
|
|
return @args; |
777
|
|
|
|
|
|
|
} |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
=head2 build |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
Receives the initialization hash and should return a new instance of the the view. By default this |
782
|
|
|
|
|
|
|
just calls C<new> on the class with the hash of args but if you need to call some other method or |
783
|
|
|
|
|
|
|
have some complex initialization work that can't be handled with L</prepare_build_args> you can |
784
|
|
|
|
|
|
|
override. |
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
=head1 CONFIGURATION |
787
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
This Catalyst Component supports the following configuation. |
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
=head2 content_type |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
The HTTP content type of the response. For example 'text/html'. Required. |
793
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
=head2 status_codes |
795
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
An ArrayRef of HTTP status codes used to provide response helpers. This is optional |
797
|
|
|
|
|
|
|
but it allows you to specify the permitted HTTP response codes that a template can |
798
|
|
|
|
|
|
|
generate. for example a NotFound view probably makes no sense to return anything |
799
|
|
|
|
|
|
|
other than a 404 Not Found code. |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
=head1 ALSO SEE |
802
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
L<Catalyst> |
804
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
=head1 AUTHORS & COPYRIGHT |
806
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
John Napiorkowski L<email:jjnapiork@cpan.org> |
808
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
=head1 LICENSE |
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
Copyright 2022, John Napiorkowski L<email:jjnapiork@cpan.org> |
812
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify |
814
|
|
|
|
|
|
|
it under the same terms as Perl itself. |
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
=cut |