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