line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package RapidApp::Module; |
2
|
|
|
|
|
|
|
|
3
|
6
|
|
|
6
|
|
3483
|
use strict; |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
158
|
|
4
|
6
|
|
|
6
|
|
29
|
use warnings; |
|
6
|
|
|
|
|
10
|
|
|
6
|
|
|
|
|
136
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
# ABSTRACT: Base class for RapidApp Modules |
7
|
|
|
|
|
|
|
|
8
|
6
|
|
|
6
|
|
27
|
use Moose; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
95
|
|
9
|
|
|
|
|
|
|
|
10
|
6
|
|
|
6
|
|
32921
|
use Clone; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
205
|
|
11
|
6
|
|
|
6
|
|
29
|
use Try::Tiny; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
349
|
|
12
|
6
|
|
|
6
|
|
2909
|
use String::Random; |
|
6
|
|
|
|
|
18286
|
|
|
6
|
|
|
|
|
267
|
|
13
|
6
|
|
|
6
|
|
40
|
use Module::Runtime; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
38
|
|
14
|
6
|
|
|
6
|
|
173
|
use Clone qw(clone); |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
209
|
|
15
|
6
|
|
|
6
|
|
33
|
use Time::HiRes qw(gettimeofday tv_interval); |
|
6
|
|
|
|
|
11
|
|
|
6
|
|
|
|
|
47
|
|
16
|
6
|
|
|
6
|
|
2231
|
use Catalyst::Utils; |
|
6
|
|
|
|
|
171893
|
|
|
6
|
|
|
|
|
177
|
|
17
|
6
|
|
|
6
|
|
47
|
use Scalar::Util qw(blessed weaken); |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
264
|
|
18
|
6
|
|
|
6
|
|
33
|
use RapidApp::JSONFunc; |
|
6
|
|
|
|
|
10
|
|
|
6
|
|
|
|
|
123
|
|
19
|
6
|
|
|
6
|
|
27
|
use RapidApp::JSON::MixedEncoder; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
339
|
|
20
|
|
|
|
|
|
|
|
21
|
6
|
|
|
6
|
|
35
|
use RapidApp::Util qw(:all); |
|
6
|
|
|
|
|
8
|
|
|
6
|
|
|
|
|
32633
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
has 'base_params' => ( is => 'ro', lazy => 1, default => sub {{}} ); |
24
|
|
|
|
|
|
|
has 'params' => ( is => 'ro', required => 0, isa => 'ArrayRef' ); |
25
|
|
|
|
|
|
|
has 'base_query_string' => ( is => 'ro', default => '' ); |
26
|
|
|
|
|
|
|
has 'exception_style' => ( is => 'ro', required => 0, default => "color: red; font-weight: bolder;" ); |
27
|
|
|
|
|
|
|
has 'auto_viewport' => ( is => 'rw', default => 0 ); |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
has 'auto_init_modules', is => 'ro', isa => 'Maybe[HashRef]', default => sub{undef}; |
30
|
|
|
|
|
|
|
# ---------- |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
has 'instance_id' => ( |
35
|
|
|
|
|
|
|
is => 'ro', lazy => 1, |
36
|
|
|
|
|
|
|
traits => ['RapidApp::Role::PerRequestBuildDefReset'], |
37
|
|
|
|
|
|
|
default => sub { |
38
|
|
|
|
|
|
|
my $self = shift; |
39
|
|
|
|
|
|
|
return 'instance-' . String::Random->new->randregex('[a-z0-9A-Z]{5}'); |
40
|
|
|
|
|
|
|
}); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
########################################################################################### |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
sub BUILD { |
46
|
220
|
|
|
220
|
0
|
825334
|
my $self= shift; |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# Init ONREQUEST_called to true to prevent ONREQUEST from running during BUILD: |
49
|
220
|
|
|
|
|
6833
|
$self->ONREQUEST_called(1); |
50
|
|
|
|
|
|
|
|
51
|
220
|
|
|
|
|
6767
|
foreach my $mod ($self->module_class_list) { |
52
|
0
|
0
|
|
|
|
0
|
my $class= ref($mod) eq ''? $mod : ref $mod eq 'HASH'? $mod->{class} : undef; |
|
|
0
|
|
|
|
|
|
53
|
0
|
0
|
|
|
|
0
|
Catalyst::Utils::ensure_class_loaded($class) if defined $class; |
54
|
|
|
|
|
|
|
}; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# Init: |
57
|
220
|
|
|
|
|
1053
|
$self->cached_per_req_attr_list; |
58
|
|
|
|
|
|
|
|
59
|
220
|
|
|
|
|
7042
|
$self->apply_actions(viewport => 'viewport'); |
60
|
220
|
|
|
|
|
6471
|
$self->apply_actions(printview => 'printview'); |
61
|
|
|
|
|
|
|
|
62
|
220
|
50
|
|
|
|
5372
|
$self->apply_init_modules(%{$self->auto_init_modules}) |
|
0
|
|
|
|
|
0
|
|
63
|
|
|
|
|
|
|
if ($self->auto_init_modules); |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
sub suburl { |
67
|
141
|
|
|
141
|
0
|
276
|
my $self = shift; |
68
|
141
|
|
|
|
|
237
|
my $url = shift; |
69
|
|
|
|
|
|
|
|
70
|
141
|
|
|
|
|
3168
|
my $new_url = $self->base_url; |
71
|
141
|
|
|
|
|
268
|
$new_url =~ s/\/$//; |
72
|
141
|
|
|
|
|
457
|
$url =~ s/^\/?/\//; |
73
|
|
|
|
|
|
|
|
74
|
141
|
|
|
|
|
299
|
$new_url .= $url; |
75
|
|
|
|
|
|
|
|
76
|
141
|
50
|
33
|
|
|
3423
|
if (defined $self->base_query_string and $self->base_query_string ne '') { |
77
|
0
|
0
|
|
|
|
0
|
$new_url .= '?' unless ($self->base_query_string =~ /^\?/); |
78
|
0
|
|
|
|
|
0
|
$new_url .= $self->base_query_string; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
141
|
|
|
|
|
2439
|
return $new_url; |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# like suburl, but also prefixes mount_url |
85
|
|
|
|
|
|
|
sub local_url { |
86
|
42
|
|
|
42
|
0
|
104
|
my ($self,$url) = @_; |
87
|
42
|
50
|
|
|
|
132
|
$url = $url ? $self->suburl($url) : $self->base_url; |
88
|
42
|
|
|
|
|
102
|
join('',$self->c->mount_url,$url) |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub urlparams { |
93
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
94
|
0
|
|
|
|
|
0
|
my $params = shift; |
95
|
|
|
|
|
|
|
|
96
|
0
|
|
|
|
|
0
|
my $new = Clone($self->base_params); |
97
|
|
|
|
|
|
|
|
98
|
0
|
0
|
0
|
|
|
0
|
if (defined $params and ref($params) eq 'HASH') { |
99
|
0
|
|
|
|
|
0
|
foreach my $k (keys %{ $params }) { |
|
0
|
|
|
|
|
0
|
|
100
|
0
|
|
|
|
|
0
|
$new->{$k} = $params->{$k}; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
} |
103
|
0
|
|
|
|
|
0
|
return $new; |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub content { |
107
|
0
|
|
|
0
|
0
|
0
|
die "Unimplemented"; |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
sub viewport { |
112
|
1
|
|
|
1
|
0
|
1293
|
my $self= shift; |
113
|
1
|
|
50
|
|
|
5
|
$self->c->stash->{current_view} ||= 'RapidApp::Viewport'; |
114
|
1
|
|
33
|
|
|
73
|
$self->c->stash->{title} ||= $self->module_name; |
115
|
1
|
|
33
|
|
|
73
|
$self->c->stash->{config_url} ||= $self->base_url; |
116
|
1
|
50
|
|
|
|
2
|
if (scalar keys %{$self->c->req->params}) { |
|
1
|
|
|
|
|
4
|
|
117
|
0
|
|
0
|
|
|
0
|
$self->c->stash->{config_params} //= { %{$self->c->req->params} }; |
|
0
|
|
|
|
|
0
|
|
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub printview { |
122
|
0
|
|
|
0
|
0
|
0
|
my $self= shift; |
123
|
0
|
|
0
|
|
|
0
|
$self->c->stash->{current_view} ||= 'RapidApp::Printview'; |
124
|
0
|
|
|
|
|
0
|
return $self->viewport; |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
sub navable { |
128
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
# Apply common stash params: |
131
|
0
|
|
|
|
|
0
|
$self->viewport; |
132
|
|
|
|
|
|
|
|
133
|
0
|
|
|
|
|
0
|
my $c = $self->c; |
134
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
0
|
my $url = delete $c->stash->{config_url}; |
136
|
0
|
0
|
|
|
|
0
|
my $params = exists $c->stash->{config_params} ? delete $c->stash->{config_params} : {}; |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
$c->stash->{panel_cfg} = { |
139
|
0
|
|
|
|
|
0
|
xtype => 'apptabpanel', |
140
|
|
|
|
|
|
|
id => 'main-load-target', |
141
|
|
|
|
|
|
|
initLoadTabs => [{ |
142
|
|
|
|
|
|
|
closable => \0, |
143
|
|
|
|
|
|
|
autoLoad => { |
144
|
|
|
|
|
|
|
url => $url, |
145
|
|
|
|
|
|
|
params => $params |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
}] |
148
|
|
|
|
|
|
|
}; |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
## -------------------------------------------------------------- |
154
|
|
|
|
|
|
|
## |
155
|
|
|
|
|
|
|
## Code from legacy roles which have been DEPRECATED: |
156
|
|
|
|
|
|
|
## |
157
|
|
|
|
|
|
|
## * RapidApp::Role::Module |
158
|
|
|
|
|
|
|
## * RapidApp::Role::Controller |
159
|
|
|
|
|
|
|
## |
160
|
|
|
|
|
|
|
## Code below was moved from roles. |
161
|
|
|
|
|
|
|
## |
162
|
|
|
|
|
|
|
## The original rationales behind why these were separate |
163
|
|
|
|
|
|
|
## no longer apply, and have been combined here |
164
|
|
|
|
|
|
|
## |
165
|
|
|
|
|
|
|
## -------------------------------------------------------------- |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
################################## |
169
|
|
|
|
|
|
|
#### Original Module Role #### |
170
|
|
|
|
|
|
|
################################## |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# In catalyst terminology, "app" is the package name of the class that extends catalyst |
174
|
|
|
|
|
|
|
# Many catalyst methods can be called from the package level |
175
|
|
|
|
|
|
|
has 'app', is => 'ro', required => 1; |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
has 'module_name' => ( is => 'ro', isa => 'Str', required => 1 ); |
178
|
|
|
|
|
|
|
has 'module_path' => ( is => 'ro', isa => 'Str', required => 1 ); |
179
|
|
|
|
|
|
|
has 'parent_module_ref' => ( is => 'ro', isa => 'Maybe[RapidApp::Module]', weak_ref => 1, required => 1); |
180
|
|
|
|
|
|
|
has 'modules_obj' => ( is => 'ro', default => sub {{}} ); |
181
|
|
|
|
|
|
|
has 'default_module' => ( is => 'rw', default => 'default_module' ); |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# This is defined in Controller role |
184
|
|
|
|
|
|
|
#has 'create_module_params' => ( is => 'ro', default => sub { {} } ); |
185
|
|
|
|
|
|
|
has 'modules_params' => ( is => 'ro', default => sub { {} } ); |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
has 'print_rapidapp_handlers_call_debug' => ( is => 'rw', isa => 'Bool', default => 0 ); |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# All purpose options: |
191
|
|
|
|
|
|
|
has 'module_options' => ( is => 'ro', lazy => 1, default => sub {{}}, traits => [ 'RapidApp::Role::PerRequestBuildDefReset' ] ); |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
has 'modules' => ( |
194
|
|
|
|
|
|
|
traits => ['Hash'], |
195
|
|
|
|
|
|
|
is => 'ro', |
196
|
|
|
|
|
|
|
isa => 'HashRef', |
197
|
|
|
|
|
|
|
default => sub { {} }, |
198
|
|
|
|
|
|
|
handles => { |
199
|
|
|
|
|
|
|
apply_modules => 'set', |
200
|
|
|
|
|
|
|
get_module => 'get', |
201
|
|
|
|
|
|
|
has_module => 'exists', |
202
|
|
|
|
|
|
|
module_class_list => 'values' |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
); |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
has 'per_request_attr_build_defaults' => ( is => 'ro', default => sub {{}}, isa => 'HashRef' ); |
208
|
|
|
|
|
|
|
has 'per_request_attr_build_not_set' => ( is => 'ro', default => sub {{}}, isa => 'HashRef' ); |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
# TODO: add back in functionality to record the time to load the module. |
211
|
|
|
|
|
|
|
# removed during the unfactor work in Github Issue #41 |
212
|
4
|
|
|
4
|
0
|
133
|
sub timed_new { (shift)->new(@_) } |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
sub cached_per_req_attr_list { |
215
|
386
|
|
|
386
|
0
|
656
|
my $self = shift; |
216
|
|
|
|
|
|
|
# XXX TODO: I think there is some Moose way of applying roles to the meta object, |
217
|
|
|
|
|
|
|
# but I'm not taking the time to look it up. This would also help with clearing the cache |
218
|
|
|
|
|
|
|
# if new attributes were defined. |
219
|
386
|
|
|
|
|
2470
|
my $attrs= (ref $self)->meta->{RapidApp_Module_PerRequestAttributeList}; |
220
|
386
|
100
|
|
|
|
7485
|
if (!defined $attrs) { |
221
|
32
|
|
|
|
|
104
|
my $attrs= [ grep { $self->should_clear_per_req($_) } $self->meta->get_all_attributes ]; |
|
2720
|
|
|
|
|
298659
|
|
222
|
|
|
|
|
|
|
# we don't want this cache to make attributes live longer than needed, so weaken the references |
223
|
32
|
|
|
|
|
3640
|
for (my $i=$#$attrs; $i>=0; $i--) { |
224
|
380
|
|
|
|
|
1045
|
weaken $attrs->[$i]; |
225
|
|
|
|
|
|
|
} |
226
|
32
|
|
|
|
|
166
|
(ref $self)->meta->{RapidApp_Module_PerRequestAttributeList}= $attrs; |
227
|
|
|
|
|
|
|
} |
228
|
386
|
|
|
|
|
1343
|
return $attrs; |
229
|
|
|
|
|
|
|
}; |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
sub should_clear_per_req { |
233
|
2720
|
|
|
2720
|
0
|
3842
|
my ($self, $attr) = @_; |
234
|
2720
|
|
|
|
|
5491
|
$attr->does('RapidApp::Role::PerRequestBuildDefReset') |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
# Does the same thing as apply_modules but also init/loads the modules |
239
|
|
|
|
|
|
|
sub apply_init_modules { |
240
|
113
|
|
|
113
|
0
|
898
|
my $self = shift; |
241
|
113
|
50
|
|
|
|
652
|
my %mods = (ref($_[0]) eq 'HASH') ? %{ $_[0] } : @_; # <-- arg as hash or hashref |
|
0
|
|
|
|
|
0
|
|
242
|
|
|
|
|
|
|
|
243
|
113
|
|
|
|
|
3678
|
$self->apply_modules(%mods); |
244
|
113
|
|
|
|
|
352
|
foreach my $module (keys %mods) { |
245
|
|
|
|
|
|
|
# Initialize every module that we just added and set ONREQUEST_called back to false: |
246
|
113
|
|
|
|
|
478
|
$self->Module($module)->ONREQUEST_called(0); |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
# 'ONREQUEST' is called once per web request. Add before modifiers to any classes that |
251
|
|
|
|
|
|
|
# need to run code at this time |
252
|
|
|
|
|
|
|
#has 'ONREQUEST_called' => ( is => 'rw', lazy => 1, default => 0, traits => [ 'RapidApp::Role::PerRequestBuildDefReset' ] ); |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
has 'ONREQUEST_called' => ( is => 'rw', lazy => 1, default => 0 ); |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
has '_lastRequestApplied' => ( is => 'rw', default => 0 ); |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
sub reset_ONREQUEST { |
259
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
260
|
0
|
|
|
|
|
0
|
$self->_lastRequestApplied(0); |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
sub ONREQUEST { |
266
|
83
|
|
|
83
|
0
|
234
|
my $self = shift; |
267
|
83
|
|
|
|
|
273
|
my ($sec0, $msec0)= gettimeofday; |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
#$self->c->log->debug(MAGENTA . '[' . $self->get_rapidapp_module_path . ']->ONREQUEST (' . $self->c->request_id . ')'); |
270
|
|
|
|
|
|
|
|
271
|
83
|
|
|
|
|
208
|
$self->_lastRequestApplied($self->c->request_id); |
272
|
|
|
|
|
|
|
|
273
|
83
|
|
|
|
|
333
|
$self->init_per_req_attrs; |
274
|
83
|
|
|
|
|
224
|
$self->c->rapidApp->markDirtyModule($self); |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
#$self->process_customprompt; |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
#$self->new_clear_per_req_attrs; |
279
|
|
|
|
|
|
|
|
280
|
83
|
|
|
|
|
415
|
$self->call_ONREQUEST_handlers; |
281
|
|
|
|
|
|
|
|
282
|
83
|
|
|
|
|
1990
|
$self->ONREQUEST_called(1); |
283
|
|
|
|
|
|
|
|
284
|
83
|
|
|
|
|
280
|
my ($sec1, $msec1)= gettimeofday; |
285
|
83
|
|
|
|
|
280
|
my $elapsed= ($sec1-$sec0)+($msec1-$msec0)*.000001; |
286
|
83
|
|
|
|
|
219
|
$self->c->stash->{onrequest_time_elapsed}+= $elapsed; |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
#$self->log->debug(sprintf(GREEN."ONREQUEST for %s took %0.3f seconds".CLEAR, $self->module_path, $elapsed)); |
289
|
83
|
|
|
|
|
5373
|
return $self; |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
sub call_ONREQUEST_handlers { |
293
|
105
|
|
|
105
|
0
|
185
|
my $self = shift; |
294
|
105
|
|
|
|
|
3336
|
$self->call_rapidapp_handlers($self->all_ONREQUEST_calls_early); |
295
|
105
|
|
|
|
|
5099
|
$self->call_rapidapp_handlers($self->all_ONREQUEST_calls); |
296
|
105
|
|
|
|
|
3491
|
$self->call_rapidapp_handlers($self->all_ONREQUEST_calls_late); |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
sub init_per_req_attrs { |
302
|
83
|
|
|
83
|
0
|
129
|
my $self = shift; |
303
|
|
|
|
|
|
|
|
304
|
83
|
|
|
|
|
124
|
foreach my $attr (@{$self->cached_per_req_attr_list}) { |
|
83
|
|
|
|
|
272
|
|
305
|
1016
|
100
|
|
|
|
2697
|
if($attr->has_value($self)) { |
306
|
661
|
100
|
|
|
|
33246
|
unless (defined $self->per_request_attr_build_defaults->{$attr->name}) { |
307
|
286
|
|
|
|
|
739
|
my $val = $attr->get_value($self); |
308
|
286
|
100
|
|
|
|
39466
|
$val = clone($val) if (ref($val)); |
309
|
286
|
|
|
|
|
7721
|
$self->per_request_attr_build_defaults->{$attr->name} = $val; |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
else { |
313
|
355
|
|
|
|
|
17688
|
$self->per_request_attr_build_not_set->{$attr->name} = 1; |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
sub reset_per_req_attrs { |
319
|
83
|
|
|
83
|
0
|
131
|
my $self = shift; |
320
|
83
|
|
|
|
|
123
|
my $c = shift; |
321
|
|
|
|
|
|
|
|
322
|
83
|
|
|
|
|
125
|
foreach my $attr (@{$self->cached_per_req_attr_list}) { |
|
83
|
|
|
|
|
253
|
|
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
# Reset to "not_set": |
325
|
1016
|
100
|
|
|
|
196841
|
if (defined $self->per_request_attr_build_not_set->{$attr->name}) { |
|
|
50
|
|
|
|
|
|
326
|
|
|
|
|
|
|
#$c->log->debug(GREEN . BOLD . ' =====> ' . $attr->name . ' (clear_value)' . CLEAR); |
327
|
355
|
|
|
|
|
931
|
$attr->clear_value($self); |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
# Reset to default: |
330
|
|
|
|
|
|
|
elsif(defined $self->per_request_attr_build_defaults->{$attr->name}) { |
331
|
661
|
|
|
|
|
14425
|
my $val = $self->per_request_attr_build_defaults->{$attr->name}; |
332
|
661
|
100
|
|
|
|
25234
|
$val = clone($val) if (ref($val)); |
333
|
|
|
|
|
|
|
#$c->log->debug(YELLOW . BOLD . ' =====> ' . $attr->name . ' (set_value)' . CLEAR); |
334
|
661
|
|
|
|
|
2319
|
$attr->set_value($self,$val); |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
# Legacy: |
339
|
83
|
50
|
|
|
|
17514
|
$self->clear_attributes if ($self->no_persist); |
340
|
|
|
|
|
|
|
} |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
#sub new_clear_per_req_attrs { |
346
|
|
|
|
|
|
|
# my $self = shift; |
347
|
|
|
|
|
|
|
# |
348
|
|
|
|
|
|
|
# #$self->ONREQUEST_called(0); |
349
|
|
|
|
|
|
|
# |
350
|
|
|
|
|
|
|
# foreach my $attr (@{$self->cached_per_req_attr_list}) { |
351
|
|
|
|
|
|
|
# # Reset to default: |
352
|
|
|
|
|
|
|
# if(defined $self->per_request_attr_build_defaults->{$attr->name}) { |
353
|
|
|
|
|
|
|
# my $val = $self->per_request_attr_build_defaults->{$attr->name}; |
354
|
|
|
|
|
|
|
# $val = clone($val) if (ref($val)); |
355
|
|
|
|
|
|
|
# $attr->set_value($self,$val); |
356
|
|
|
|
|
|
|
# } |
357
|
|
|
|
|
|
|
# # Initialize default: |
358
|
|
|
|
|
|
|
# else { |
359
|
|
|
|
|
|
|
# my $val = $attr->get_value($self); |
360
|
|
|
|
|
|
|
# $val = clone($val) if (ref($val)); |
361
|
|
|
|
|
|
|
# $self->per_request_attr_build_defaults->{$attr->name} = $val; |
362
|
|
|
|
|
|
|
# } |
363
|
|
|
|
|
|
|
# } |
364
|
|
|
|
|
|
|
# |
365
|
|
|
|
|
|
|
# # Legacy: |
366
|
|
|
|
|
|
|
# $self->clear_attributes if ($self->no_persist); |
367
|
|
|
|
|
|
|
#} |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
sub THIS_MODULE { |
373
|
1395
|
|
|
1395
|
0
|
2068
|
my $self = shift; |
374
|
1395
|
100
|
|
|
|
2660
|
return $self unless (defined $self->c); |
375
|
|
|
|
|
|
|
|
376
|
519
|
100
|
66
|
|
|
928
|
return $self->ONREQUEST if (defined $self->c && $self->c->request_id != $self->_lastRequestApplied); |
377
|
436
|
|
|
|
|
2360
|
return $self; |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
# Gets a Module by / delim path |
382
|
|
|
|
|
|
|
sub get_Module { |
383
|
4
|
|
|
4
|
0
|
9
|
my $self = shift; |
384
|
4
|
50
|
|
|
|
18
|
my $path = shift or return $self->THIS_MODULE; |
385
|
|
|
|
|
|
|
|
386
|
4
|
|
|
|
|
20
|
my @parts = split('/',$path); |
387
|
4
|
|
|
|
|
16
|
my $first = shift @parts; |
388
|
|
|
|
|
|
|
# If $first is undef then the path is absolute (starts with '/'): |
389
|
4
|
50
|
|
|
|
15
|
unless ($first) { |
390
|
0
|
|
|
|
|
0
|
my $topModule = $self->topmost_module; |
391
|
|
|
|
|
|
|
# New: support returning modules when the module_root_namespace is supplied in the path: |
392
|
0
|
0
|
0
|
|
|
0
|
shift @parts if ( |
393
|
|
|
|
|
|
|
!$topModule->has_module($parts[0]) && |
394
|
|
|
|
|
|
|
$parts[0] eq $self->app->module_root_namespace |
395
|
|
|
|
|
|
|
); |
396
|
|
|
|
|
|
|
|
397
|
0
|
|
|
|
|
0
|
return $topModule->get_Module(join('/',@parts)); |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
# If there are no more parts in the path, then the name is a direct submodule: |
401
|
4
|
50
|
|
|
|
45
|
return $self->Module($first) unless (scalar @parts > 0); |
402
|
|
|
|
|
|
|
|
403
|
0
|
|
|
|
|
0
|
return $self->Module($first)->get_Module(join('/',@parts)); |
404
|
|
|
|
|
|
|
} |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
sub Module { |
409
|
632
|
|
|
632
|
0
|
1121
|
my $self = shift; |
410
|
632
|
|
|
|
|
1127
|
my $name = shift; |
411
|
632
|
|
|
|
|
1014
|
my $no_onreq = shift; |
412
|
|
|
|
|
|
|
|
413
|
632
|
100
|
|
|
|
1755
|
$self->_load_module($name) or confess "Failed to load Module '$name'"; |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
#return $self->modules_obj->{$name} if ($no_onreq); |
416
|
628
|
|
|
|
|
12478
|
return $self->modules_obj->{$name}->THIS_MODULE; |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
sub _load_module { |
421
|
672
|
|
|
672
|
|
1016
|
my $self = shift; |
422
|
672
|
50
|
|
|
|
1692
|
my $name = shift or return 0; |
423
|
672
|
100
|
|
|
|
19006
|
return 0 unless ($self->has_module($name)); |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
#my $class_name = $self->modules->{$name} or return 0; |
426
|
668
|
|
|
|
|
17780
|
my $class_name = $self->get_module($name); |
427
|
668
|
|
|
|
|
1033
|
my $params; |
428
|
668
|
100
|
|
|
|
1859
|
if (ref($class_name) eq 'HASH') { |
429
|
655
|
|
|
|
|
1404
|
$params = $class_name->{params}; |
430
|
655
|
50
|
|
|
|
1757
|
$class_name = $class_name->{class} or die "Missing required parameter 'class'"; |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
|
433
|
668
|
100
|
66
|
|
|
14531
|
return 1 if (defined $self->modules_obj->{$name} and ref($self->modules_obj->{$name}) eq $class_name); |
434
|
|
|
|
|
|
|
|
435
|
216
|
50
|
|
|
|
945
|
my $Object = $self->create_module($name,$class_name,$params) or die "Failed to create new $class_name object"; |
436
|
|
|
|
|
|
|
|
437
|
216
|
|
|
|
|
5052
|
$self->modules_obj->{$name} = $Object; |
438
|
|
|
|
|
|
|
|
439
|
216
|
|
|
|
|
800
|
return 1; |
440
|
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
sub create_module { |
443
|
216
|
|
|
216
|
0
|
440
|
my $self = shift; |
444
|
216
|
|
|
|
|
424
|
my $name = shift; |
445
|
216
|
|
|
|
|
370
|
my $class_name = shift; |
446
|
216
|
|
|
|
|
384
|
my $params = shift; |
447
|
|
|
|
|
|
|
|
448
|
216
|
50
|
|
|
|
751
|
die "Bad module name '$name' -- cannot contain '/'" if ($name =~ /\//); |
449
|
|
|
|
|
|
|
|
450
|
216
|
|
|
|
|
1136
|
Module::Runtime::require_module($class_name); |
451
|
|
|
|
|
|
|
|
452
|
216
|
100
|
|
|
|
7361
|
$params = $self->create_module_params unless (defined $params); |
453
|
|
|
|
|
|
|
|
454
|
216
|
50
|
|
|
|
5528
|
if (defined $self->modules_params->{$name}) { |
455
|
0
|
|
|
|
|
0
|
foreach my $k (keys %{$self->modules_params->{$name}}) { |
|
0
|
|
|
|
|
0
|
|
456
|
0
|
|
|
|
|
0
|
$params->{$k} = $self->modules_params->{$name}->{$k}; |
457
|
|
|
|
|
|
|
} |
458
|
|
|
|
|
|
|
} |
459
|
|
|
|
|
|
|
|
460
|
216
|
|
|
|
|
4649
|
$params->{app} = $self->app; |
461
|
216
|
|
|
|
|
685
|
$params->{module_name} = $name; |
462
|
216
|
|
|
|
|
4842
|
$params->{module_path} = $self->module_path; |
463
|
216
|
100
|
|
|
|
1235
|
$params->{module_path} .= '/' unless substr($params->{module_path}, -1) eq '/'; |
464
|
216
|
|
|
|
|
473
|
$params->{module_path} .= $name; |
465
|
216
|
|
|
|
|
456
|
$params->{parent_module_ref} = $self; |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
# Colorful console messages, non-standard, replaced with normal logging below: |
469
|
|
|
|
|
|
|
#print STDERR |
470
|
|
|
|
|
|
|
# ' >> ' . |
471
|
|
|
|
|
|
|
# CYAN . "Load: " . BOLD . $params->{module_path} . CLEAR . |
472
|
|
|
|
|
|
|
# CYAN . " [$class_name]" . CLEAR . "\n" |
473
|
|
|
|
|
|
|
#if ($self->app->debug); |
474
|
|
|
|
|
|
|
|
475
|
216
|
|
|
|
|
1091
|
my $start = [gettimeofday]; |
476
|
|
|
|
|
|
|
|
477
|
216
|
50
|
|
|
|
6244
|
my $Object = $class_name->new($params) or die "Failed to create module instance ($class_name)"; |
478
|
216
|
50
|
|
|
|
3711
|
die "$class_name is not a valid RapidApp Module" unless ($Object->isa('RapidApp::Module')); |
479
|
|
|
|
|
|
|
|
480
|
216
|
|
|
|
|
4919
|
my $c = $self->app; |
481
|
|
|
|
|
|
|
$c->log->debug( join('', |
482
|
216
|
50
|
|
|
|
1509
|
" >> Loaded: ",$params->{module_path}," [$class_name] ", |
483
|
|
|
|
|
|
|
sprintf("(%0.3fs)",tv_interval($start)) |
484
|
|
|
|
|
|
|
)) if ($c->debug); |
485
|
|
|
|
|
|
|
|
486
|
216
|
|
|
|
|
1470
|
return $Object; |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
sub parent_module { |
490
|
756
|
|
|
756
|
0
|
9157
|
my $self = shift; |
491
|
756
|
100
|
|
|
|
16250
|
return $self->parent_module_ref ? $self->parent_module_ref->THIS_MODULE : undef; |
492
|
|
|
|
|
|
|
} |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
sub topmost_module { |
496
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
497
|
0
|
0
|
|
|
|
0
|
return $self unless (defined $self->parent_module); |
498
|
0
|
|
|
|
|
0
|
return $self->parent_module->topmost_module; |
499
|
|
|
|
|
|
|
} |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
sub parent_by_name { |
503
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
504
|
0
|
|
|
|
|
0
|
my $name = shift; |
505
|
0
|
0
|
|
|
|
0
|
return $self if (lc($self->module_name) eq lc($name)); |
506
|
0
|
0
|
|
|
|
0
|
return undef unless (defined $self->parent_module); |
507
|
0
|
|
|
|
|
0
|
return $self->parent_module->parent_by_name($name); |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
sub applyIf_module_options { |
513
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
514
|
0
|
0
|
|
|
|
0
|
my %new = (ref($_[0]) eq 'HASH') ? %{ $_[0] } : @_; # <-- arg as hash or hashref |
|
0
|
|
|
|
|
0
|
|
515
|
|
|
|
|
|
|
|
516
|
0
|
|
|
|
|
0
|
my %unset = (); |
517
|
0
|
|
|
|
|
0
|
foreach my $opt (keys %new) { |
518
|
0
|
0
|
|
|
|
0
|
next if (defined $self->module_options->{$opt}); |
519
|
0
|
|
|
|
|
0
|
$unset{$opt} = $new{$opt}; |
520
|
|
|
|
|
|
|
} |
521
|
|
|
|
|
|
|
|
522
|
0
|
|
|
|
|
0
|
return $self->apply_module_options(%unset); |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
sub apply_module_options { |
527
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
528
|
0
|
0
|
|
|
|
0
|
my %new = (ref($_[0]) eq 'HASH') ? %{ $_[0] } : @_; # <-- arg as hash or hashref |
|
0
|
|
|
|
|
0
|
|
529
|
|
|
|
|
|
|
|
530
|
0
|
|
|
|
|
0
|
%{ $self->module_options } = ( |
531
|
0
|
|
|
|
|
0
|
%{ $self->module_options }, |
|
0
|
|
|
|
|
0
|
|
532
|
|
|
|
|
|
|
%new |
533
|
|
|
|
|
|
|
); |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
sub get_module_option { |
537
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
538
|
0
|
|
|
|
|
0
|
my $opt = shift; |
539
|
0
|
|
|
|
|
0
|
return $self->module_options->{$opt}; |
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
has 'ONREQUEST_calls' => ( |
544
|
|
|
|
|
|
|
traits => [ 'Array' ], |
545
|
|
|
|
|
|
|
is => 'ro', |
546
|
|
|
|
|
|
|
isa => 'ArrayRef[RapidApp::Handler]', |
547
|
|
|
|
|
|
|
default => sub { [] }, |
548
|
|
|
|
|
|
|
handles => { |
549
|
|
|
|
|
|
|
all_ONREQUEST_calls => 'elements', |
550
|
|
|
|
|
|
|
add_ONREQUEST_calls => 'push', |
551
|
|
|
|
|
|
|
has_no_ONREQUEST_calls => 'is_empty', |
552
|
|
|
|
|
|
|
} |
553
|
|
|
|
|
|
|
); |
554
|
|
|
|
|
|
|
around 'add_ONREQUEST_calls' => __PACKAGE__->add_ONREQUEST_calls_modifier; |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
has 'ONREQUEST_calls_early' => ( |
557
|
|
|
|
|
|
|
traits => [ 'Array' ], |
558
|
|
|
|
|
|
|
is => 'ro', |
559
|
|
|
|
|
|
|
isa => 'ArrayRef[RapidApp::Handler]', |
560
|
|
|
|
|
|
|
default => sub { [] }, |
561
|
|
|
|
|
|
|
handles => { |
562
|
|
|
|
|
|
|
all_ONREQUEST_calls_early => 'elements', |
563
|
|
|
|
|
|
|
add_ONREQUEST_calls_early => 'push', |
564
|
|
|
|
|
|
|
has_no_ONREQUEST_calls_early => 'is_empty', |
565
|
|
|
|
|
|
|
} |
566
|
|
|
|
|
|
|
); |
567
|
|
|
|
|
|
|
around 'add_ONREQUEST_calls_early' => __PACKAGE__->add_ONREQUEST_calls_modifier; |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
has 'ONREQUEST_calls_late' => ( |
570
|
|
|
|
|
|
|
traits => [ 'Array' ], |
571
|
|
|
|
|
|
|
is => 'ro', |
572
|
|
|
|
|
|
|
isa => 'ArrayRef[RapidApp::Handler]', |
573
|
|
|
|
|
|
|
default => sub { [] }, |
574
|
|
|
|
|
|
|
handles => { |
575
|
|
|
|
|
|
|
all_ONREQUEST_calls_late => 'elements', |
576
|
|
|
|
|
|
|
add_ONREQUEST_calls_late => 'push', |
577
|
|
|
|
|
|
|
has_no_ONREQUEST_calls_late => 'is_empty', |
578
|
|
|
|
|
|
|
} |
579
|
|
|
|
|
|
|
); |
580
|
|
|
|
|
|
|
around 'add_ONREQUEST_calls_late' => __PACKAGE__->add_ONREQUEST_calls_modifier; |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
sub add_ONREQUEST_calls_modifier { |
583
|
|
|
|
|
|
|
return sub { |
584
|
509
|
|
|
509
|
|
7551
|
my $orig = shift; |
585
|
509
|
|
|
|
|
719
|
my $self = shift; |
586
|
509
|
50
|
|
|
|
1147
|
return $self->$orig(@_) if (ref($_[0])); |
587
|
|
|
|
|
|
|
|
588
|
509
|
|
|
|
|
917
|
my @new = (); |
589
|
509
|
|
|
|
|
918
|
foreach my $item (@_) { |
590
|
509
|
|
|
|
|
1870
|
push @new, RapidApp::Handler->new( |
591
|
|
|
|
|
|
|
method => $item, |
592
|
|
|
|
|
|
|
scope => $self |
593
|
|
|
|
|
|
|
); |
594
|
|
|
|
|
|
|
} |
595
|
509
|
|
|
|
|
18863
|
return $self->$orig(@new); |
596
|
23
|
|
|
23
|
0
|
222
|
}; |
597
|
|
|
|
|
|
|
} |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
sub call_rapidapp_handlers { |
600
|
361
|
|
|
361
|
0
|
489
|
my $self = shift; |
601
|
361
|
|
|
|
|
679
|
foreach my $Handler (@_) { |
602
|
175
|
50
|
|
|
|
817
|
die 'not a RapidApp::Handler' unless (ref($Handler) eq 'RapidApp::Handler'); |
603
|
|
|
|
|
|
|
|
604
|
175
|
50
|
|
|
|
4278
|
if($self->print_rapidapp_handlers_call_debug) { |
605
|
0
|
|
|
|
|
0
|
my $msg = YELLOW . '->call_rapidapp_handlers[' . $self->get_rapidapp_module_path . '] ' . CLEAR; |
606
|
0
|
|
|
|
|
0
|
$msg .= GREEN; |
607
|
0
|
0
|
|
|
|
0
|
if (defined $Handler->scope) { |
608
|
0
|
|
|
|
|
0
|
$msg .= '(' . ref($Handler->scope); |
609
|
0
|
0
|
|
|
|
0
|
if ($Handler->scope->isa('RapidApp::Module')) { |
610
|
0
|
|
|
|
|
0
|
$msg .= CLEAR . BLUE . ' ' . $Handler->scope->get_rapidapp_module_path; |
611
|
|
|
|
|
|
|
} |
612
|
0
|
|
|
|
|
0
|
$msg .= CLEAR . GREEN . ')' . CLEAR; |
613
|
|
|
|
|
|
|
} |
614
|
|
|
|
|
|
|
else { |
615
|
0
|
|
|
|
|
0
|
$msg .= '(no scope)'; |
616
|
|
|
|
|
|
|
} |
617
|
|
|
|
|
|
|
|
618
|
0
|
0
|
|
|
|
0
|
if (defined $Handler->method) { |
619
|
0
|
|
|
|
|
0
|
$msg .= BOLD . '->' . $Handler->method . CLEAR; |
620
|
|
|
|
|
|
|
} |
621
|
|
|
|
|
|
|
else { |
622
|
0
|
|
|
|
|
0
|
$msg .= BOLD . '==>CODEREF->()' . CLEAR; |
623
|
|
|
|
|
|
|
} |
624
|
|
|
|
|
|
|
|
625
|
0
|
|
|
|
|
0
|
$self->app->log->debug($msg); |
626
|
|
|
|
|
|
|
} |
627
|
|
|
|
|
|
|
|
628
|
175
|
|
|
|
|
532
|
$Handler->call; |
629
|
|
|
|
|
|
|
} |
630
|
|
|
|
|
|
|
} |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
#before 'ONREQUEST' => sub { |
633
|
|
|
|
|
|
|
# my $self = shift; |
634
|
|
|
|
|
|
|
# $self->call_rapidapp_handlers($self->all_ONREQUEST_calls_early); |
635
|
|
|
|
|
|
|
#}; |
636
|
|
|
|
|
|
|
# |
637
|
|
|
|
|
|
|
#after 'ONREQUEST' => sub { |
638
|
|
|
|
|
|
|
# my $self = shift; |
639
|
|
|
|
|
|
|
# $self->call_rapidapp_handlers($self->all_ONREQUEST_calls_late); |
640
|
|
|
|
|
|
|
#}; |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
# All purpose flags (true/false) settings |
644
|
|
|
|
|
|
|
has 'flags' => ( |
645
|
|
|
|
|
|
|
traits => [ |
646
|
|
|
|
|
|
|
'Hash', |
647
|
|
|
|
|
|
|
'RapidApp::Role::PerRequestBuildDefReset' |
648
|
|
|
|
|
|
|
], |
649
|
|
|
|
|
|
|
is => 'ro', |
650
|
|
|
|
|
|
|
isa => 'HashRef[Bool]', |
651
|
|
|
|
|
|
|
default => sub { {} }, |
652
|
|
|
|
|
|
|
handles => { |
653
|
|
|
|
|
|
|
apply_flags => 'set', |
654
|
|
|
|
|
|
|
has_flag => 'get', |
655
|
|
|
|
|
|
|
delete_flag => 'delete', |
656
|
|
|
|
|
|
|
flag_defined => 'exists', |
657
|
|
|
|
|
|
|
all_flags => 'elements' |
658
|
|
|
|
|
|
|
}, |
659
|
|
|
|
|
|
|
); |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
# function for debugging purposes - returns a string of the module path |
663
|
|
|
|
|
|
|
sub get_rapidapp_module_path { |
664
|
0
|
|
|
0
|
0
|
0
|
return (shift)->module_path; |
665
|
|
|
|
|
|
|
} |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
has 'customprompt_button' => ( |
669
|
|
|
|
|
|
|
is => 'rw', |
670
|
|
|
|
|
|
|
isa => 'Maybe[Str]', |
671
|
|
|
|
|
|
|
traits => [ 'RapidApp::Role::PerRequestBuildDefReset' ], |
672
|
|
|
|
|
|
|
lazy => 1, |
673
|
|
|
|
|
|
|
default => sub { |
674
|
|
|
|
|
|
|
my $self = shift; |
675
|
|
|
|
|
|
|
return $self->c->req->header('X-RapidApp-CustomPrompt-Button') || $self->c->req->params->{'X-RapidApp-CustomPrompt-Button'}; |
676
|
|
|
|
|
|
|
} |
677
|
|
|
|
|
|
|
); |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
has 'customprompt_data' => ( |
681
|
|
|
|
|
|
|
is => 'rw', |
682
|
|
|
|
|
|
|
isa => 'HashRef', |
683
|
|
|
|
|
|
|
traits => [ 'RapidApp::Role::PerRequestBuildDefReset' ], |
684
|
|
|
|
|
|
|
lazy => 1, |
685
|
|
|
|
|
|
|
default => sub { |
686
|
|
|
|
|
|
|
my $self = shift; |
687
|
|
|
|
|
|
|
my $rawdata = $self->c->req->header('X-RapidApp-CustomPrompt-Data') || $self->c->req->params->{'X-RapidApp-CustomPrompt-Data'}; |
688
|
|
|
|
|
|
|
return {} unless (defined $rawdata); |
689
|
|
|
|
|
|
|
return $self->json->decode($rawdata); |
690
|
|
|
|
|
|
|
} |
691
|
|
|
|
|
|
|
); |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
################################## |
695
|
|
|
|
|
|
|
#### Original Controller Role #### |
696
|
|
|
|
|
|
|
################################## |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
has 'base_url' => ( |
700
|
|
|
|
|
|
|
is => 'rw', lazy => 1, default => sub { |
701
|
|
|
|
|
|
|
my $self = shift; |
702
|
|
|
|
|
|
|
my $ns = $self->app->module_root_namespace; |
703
|
|
|
|
|
|
|
$ns = $ns eq '' ? $ns : '/' . $ns; |
704
|
|
|
|
|
|
|
my $parentUrl= defined $self->parent_module? $self->parent_module->base_url.'/' : $ns; |
705
|
|
|
|
|
|
|
return $parentUrl . $self->{module_name}; |
706
|
|
|
|
|
|
|
}, |
707
|
|
|
|
|
|
|
traits => [ 'RapidApp::Role::PerRequestBuildDefReset' ] |
708
|
|
|
|
|
|
|
); |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
#has 'extra_actions' => ( is => 'ro', default => sub {{}} ); |
711
|
|
|
|
|
|
|
has 'default_action' => ( is => 'ro', default => undef ); |
712
|
|
|
|
|
|
|
has 'render_as_json' => ( is => 'rw', default => 1, traits => [ 'RapidApp::Role::PerRequestBuildDefReset' ] ); |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
# NEW: if true, sub-args (of url path) are passed in even if the sub path does |
715
|
|
|
|
|
|
|
# not exist as a defined action or sub-module. TODO: refactor and use built-in Catalyst |
716
|
|
|
|
|
|
|
# functionality for controller actions. ALL of Module/Controller should be refactored |
717
|
|
|
|
|
|
|
# into proper sub-classes of Catalyst controllers |
718
|
|
|
|
|
|
|
has 'accept_subargs', is => 'rw', isa => 'Bool', default => 0; |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
has 'actions' => ( |
721
|
|
|
|
|
|
|
traits => ['Hash'], |
722
|
|
|
|
|
|
|
is => 'ro', |
723
|
|
|
|
|
|
|
isa => 'HashRef', |
724
|
|
|
|
|
|
|
default => sub { {} }, |
725
|
|
|
|
|
|
|
handles => { |
726
|
|
|
|
|
|
|
apply_actions => 'set', |
727
|
|
|
|
|
|
|
get_action => 'get', |
728
|
|
|
|
|
|
|
has_action => 'exists' |
729
|
|
|
|
|
|
|
} |
730
|
|
|
|
|
|
|
); |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
# In catalyst terminology, "c" is the catalyst instance, embodying a request. |
733
|
3333
|
|
|
3333
|
0
|
9654
|
sub c { RapidApp->active_request_context } |
734
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
# The current logger object, probably the same as ->c->log, but maybe not. |
736
|
0
|
|
|
0
|
0
|
0
|
sub log { (shift)->app->log } |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
has 'no_persist' => ( is => 'rw', lazy => 1, default => sub { |
740
|
|
|
|
|
|
|
my $self = shift; |
741
|
|
|
|
|
|
|
# inherit the parent's no_persist setting if its set: |
742
|
|
|
|
|
|
|
return $self->parent_module->no_persist if ( |
743
|
|
|
|
|
|
|
defined $self->parent_module and |
744
|
|
|
|
|
|
|
defined $self->parent_module->no_persist |
745
|
|
|
|
|
|
|
); |
746
|
|
|
|
|
|
|
return undef; |
747
|
|
|
|
|
|
|
}); |
748
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
has 'render_append' => ( is => 'rw', default => '', isa => 'Str' ); |
750
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
sub add_render_append { |
752
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
753
|
0
|
0
|
|
|
|
0
|
my $add or return; |
754
|
0
|
0
|
|
|
|
0
|
die 'ref encountered, string expected' if ref($add); |
755
|
|
|
|
|
|
|
|
756
|
0
|
|
|
|
|
0
|
my $cur = $self->render_append; |
757
|
0
|
|
|
|
|
0
|
return $self->render_append( $cur . $add ); |
758
|
|
|
|
|
|
|
} |
759
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
has 'no_json_ref_types' => ( is => 'ro', default => sub { |
762
|
|
|
|
|
|
|
return { |
763
|
|
|
|
|
|
|
'IO::File' => 1 |
764
|
|
|
|
|
|
|
} |
765
|
|
|
|
|
|
|
}); |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
has 'create_module_params' => ( is => 'ro', lazy => 1, default => sub {{}} ); |
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
has 'json' => ( is => 'ro', lazy_build => 1 ); |
770
|
|
|
|
|
|
|
sub _build_json { |
771
|
3
|
|
|
3
|
|
7
|
my $self = shift; |
772
|
|
|
|
|
|
|
#$self->log->warn((ref $self)."->json still being used"); |
773
|
3
|
|
|
|
|
29
|
return RapidApp::JSON::MixedEncoder->new; |
774
|
|
|
|
|
|
|
} |
775
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
sub JSON_encode { |
777
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
778
|
0
|
|
|
|
|
0
|
return $self->json->encode(shift); |
779
|
|
|
|
|
|
|
} |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
## TODO: REMOVE 'simulateRequest' --- |
783
|
|
|
|
|
|
|
# This method attempts to set up a catalyst request instance such that a new request can be executed |
784
|
|
|
|
|
|
|
# to a different module and with different parameters and HTTP headers than were used for the main |
785
|
|
|
|
|
|
|
# request. |
786
|
|
|
|
|
|
|
sub simulateRequest { |
787
|
0
|
|
|
0
|
0
|
0
|
my ($self, $req)= @_; |
788
|
|
|
|
|
|
|
|
789
|
0
|
|
|
|
|
0
|
my $c = RapidApp->active_request_context; |
790
|
|
|
|
|
|
|
|
791
|
0
|
|
|
|
|
0
|
my $tempResp= Catalyst::Response->new(); |
792
|
|
|
|
|
|
|
|
793
|
0
|
|
|
|
|
0
|
my $origReq= $c->request; |
794
|
0
|
|
|
|
|
0
|
my $origResp= $c->response; |
795
|
0
|
|
|
|
|
0
|
my $origStash= $c->stash; |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
try { |
798
|
0
|
|
|
0
|
|
0
|
$c->request($req); |
799
|
0
|
|
|
|
|
0
|
$c->response($tempResp); |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
# This is dangerous both any way you do it. We could make an empty stash, but then might lose important |
802
|
|
|
|
|
|
|
# settings (like those set by ModuleDispatcher) |
803
|
0
|
|
|
|
|
0
|
$c->stash({ %$origStash }); |
804
|
|
|
|
|
|
|
|
805
|
0
|
|
|
|
|
0
|
my $path= $req->uri->path; |
806
|
0
|
|
|
|
|
0
|
$path =~ s|^/||; |
807
|
0
|
|
|
|
|
0
|
my @args= split('/', $path); |
808
|
0
|
|
|
|
|
0
|
$self->c->log->debug("Simulate Request: \"".join('", "', @args)); |
809
|
0
|
|
|
|
|
0
|
my $ctl_ret= $self->Controller($c, @args); |
810
|
|
|
|
|
|
|
|
811
|
0
|
0
|
|
|
|
0
|
$c->log->debug('controller return: '.(length($ctl_ret) > 20? (ref $ctl_ret).' length='.length($ctl_ret) : $ctl_ret)); |
812
|
0
|
0
|
|
|
|
0
|
$c->log->debug('body: '.(length($tempResp->body) > 20? (ref $tempResp->body).' length='.length($tempResp->body) : $tempResp->body)); |
813
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
# execute the specified view, if needed |
815
|
0
|
0
|
|
|
|
0
|
if (!defined $c->res->body) { |
816
|
0
|
|
0
|
|
|
0
|
my $view= $self->c->stash->{current_view_instance} || $c->view($c->stash->{current_view}); |
817
|
0
|
|
|
|
|
0
|
$view->process($c); |
818
|
|
|
|
|
|
|
} |
819
|
|
|
|
|
|
|
|
820
|
0
|
|
|
|
|
0
|
$c->request($origReq); |
821
|
0
|
|
|
|
|
0
|
$c->response($origResp); |
822
|
0
|
|
|
|
|
0
|
$c->stash($origStash); |
823
|
|
|
|
|
|
|
} |
824
|
|
|
|
|
|
|
catch { |
825
|
0
|
|
|
0
|
|
0
|
$c->request($origReq); |
826
|
0
|
|
|
|
|
0
|
$c->response($origResp); |
827
|
0
|
|
|
|
|
0
|
$c->stash($origStash); |
828
|
0
|
|
|
|
|
0
|
die $_; |
829
|
0
|
|
|
|
|
0
|
}; |
830
|
0
|
|
|
|
|
0
|
return $tempResp; |
831
|
|
|
|
|
|
|
} |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
sub simulateRequestToSubUrl { |
834
|
0
|
|
|
0
|
0
|
0
|
my ($self, $uri, @params)= @_; |
835
|
0
|
0
|
0
|
|
|
0
|
blessed($uri) && $uri->isa('URI') or $uri= URI->new($uri); |
836
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
# if parameters were part of the URI, extract them first, then possibly override them with @params |
838
|
|
|
|
|
|
|
# Note that "array-style" URI params will be returned as duplicate key entries, so we have to do some work to |
839
|
|
|
|
|
|
|
# assemble the values into lists to match the way you'd expect it to work. |
840
|
0
|
|
|
|
|
0
|
my @uriParams= $uri->query_form; |
841
|
0
|
|
|
|
|
0
|
my %paramHash; |
842
|
0
|
|
|
|
|
0
|
for (my $i=0; $i < $#uriParams; $i+= 2) { |
843
|
0
|
|
|
|
|
0
|
my ($key, $val)= ($uriParams[$i], $uriParams[$i+1]); |
844
|
|
|
|
|
|
|
$paramHash{$key}= (!defined $paramHash{$key})? |
845
|
|
|
|
|
|
|
$val |
846
|
|
|
|
|
|
|
: (ref $paramHash{$key} ne 'ARRAY')? |
847
|
|
|
|
|
|
|
[ $paramHash{$key}, $val ] |
848
|
0
|
0
|
|
|
|
0
|
: [ @{$paramHash{$key}}, $val ]; |
|
0
|
0
|
|
|
|
0
|
|
849
|
|
|
|
|
|
|
} |
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
# add in the supplied parameters |
852
|
0
|
|
|
|
|
0
|
%paramHash= ( %paramHash, @params ); |
853
|
|
|
|
|
|
|
|
854
|
0
|
|
|
|
|
0
|
my $req= Catalyst::Request->new( uri => $uri, parameters => \%paramHash ); |
855
|
|
|
|
|
|
|
|
856
|
0
|
|
|
|
|
0
|
return $self->simulateRequest($req); |
857
|
|
|
|
|
|
|
} |
858
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
sub simulateRequestToSubUrl_asString { |
860
|
0
|
|
|
0
|
0
|
0
|
my $self= shift; |
861
|
0
|
|
|
|
|
0
|
my $resp= $self->simulateRequestToSubUrl(@_); |
862
|
0
|
0
|
|
|
|
0
|
$resp->status == 200 |
863
|
|
|
|
|
|
|
or die "Simulated request to ".$_[0]." returned status ".$resp->status; |
864
|
0
|
|
|
|
|
0
|
my $ret= $resp->body; |
865
|
0
|
0
|
|
|
|
0
|
if (ref $ret) { |
866
|
0
|
|
|
|
|
0
|
my $fd= $ret; |
867
|
0
|
|
|
|
|
0
|
local $/= undef; |
868
|
0
|
|
|
|
|
0
|
$ret= <$fd>; |
869
|
0
|
|
|
|
|
0
|
$fd->close; |
870
|
|
|
|
|
|
|
} |
871
|
0
|
|
|
|
|
0
|
return $ret; |
872
|
|
|
|
|
|
|
} |
873
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
# Initializes variables of the controller based on the details of the current request being handled. |
875
|
|
|
|
|
|
|
# This is a stub for 'after's and 'before's and overrides. |
876
|
|
|
|
52
|
0
|
|
sub prepare_controller { |
877
|
|
|
|
|
|
|
} |
878
|
|
|
|
|
|
|
|
879
|
|
|
|
|
|
|
=head2 Controller( $catalyst, @pathArguments ) |
880
|
|
|
|
|
|
|
|
881
|
|
|
|
|
|
|
This method handles a request. |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
=cut |
884
|
|
|
|
|
|
|
sub Controller { |
885
|
52
|
|
|
52
|
1
|
160
|
my ($self, $c, @args) = @_; |
886
|
|
|
|
|
|
|
|
887
|
52
|
|
|
|
|
303
|
$self->prepare_controller(@args); |
888
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
# dispatch the request to the appropriate handler |
890
|
|
|
|
|
|
|
|
891
|
52
|
50
|
|
|
|
169
|
$c->log->debug('--> ' . |
892
|
|
|
|
|
|
|
GREEN.BOLD . ref($self) . CLEAR . ' ' . |
893
|
|
|
|
|
|
|
GREEN . join('/',@args) . CLEAR |
894
|
|
|
|
|
|
|
) if ($c->debug); |
895
|
|
|
|
|
|
|
|
896
|
52
|
|
|
|
|
364
|
$self->controller_dispatch(@args); |
897
|
|
|
|
|
|
|
} |
898
|
|
|
|
|
|
|
|
899
|
|
|
|
|
|
|
# module or action: |
900
|
|
|
|
|
|
|
sub has_subarg { |
901
|
23
|
|
|
23
|
0
|
66
|
my ($self, $opt) = @_; |
902
|
23
|
50
|
33
|
|
|
744
|
return ($opt && ( |
903
|
|
|
|
|
|
|
$self->has_module($opt) || |
904
|
|
|
|
|
|
|
$self->has_action($opt) |
905
|
|
|
|
|
|
|
)) ? 1 : 0; |
906
|
|
|
|
|
|
|
} |
907
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
has 'get_local_args', is => 'ro', isa => 'Maybe[CodeRef]', lazy => 1, default => undef; |
910
|
|
|
|
|
|
|
|
911
|
|
|
|
|
|
|
sub local_args { |
912
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
913
|
|
|
|
|
|
|
|
914
|
0
|
0
|
|
|
|
0
|
return $self->get_local_args->() if ($self->get_local_args); |
915
|
|
|
|
|
|
|
|
916
|
0
|
|
|
|
|
0
|
my $path = '/' . $self->c->req->path; |
917
|
0
|
|
|
|
|
0
|
my $base = quotemeta($self->base_url . '/'); |
918
|
0
|
|
|
|
|
0
|
my ($match) = ($path =~ /^${base}(.+$)/); |
919
|
0
|
0
|
|
|
|
0
|
my $argpath = defined $match ? $match : ''; |
920
|
0
|
|
|
|
|
0
|
return split('/',$argpath); |
921
|
|
|
|
|
|
|
} |
922
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
# is this being used anyplace?? |
924
|
|
|
|
|
|
|
sub clear_attributes { |
925
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
926
|
0
|
|
|
|
|
0
|
for my $attr ($self->meta->get_all_attributes) { |
927
|
0
|
0
|
|
|
|
0
|
next if ($attr->name eq 'actions'); |
928
|
0
|
0
|
0
|
|
|
0
|
$attr->clear_value($self) if ($attr->is_lazy or $attr->has_clearer); |
929
|
|
|
|
|
|
|
} |
930
|
|
|
|
|
|
|
} |
931
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
=head2 controller_dispatch( @args ) |
934
|
|
|
|
|
|
|
|
935
|
|
|
|
|
|
|
controller_dispatch performs the standard RapidApp dispatch processing for a Module. |
936
|
|
|
|
|
|
|
|
937
|
|
|
|
|
|
|
=over |
938
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
=item * |
940
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
If the first argument names an action, the action is executed. |
942
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
=item * |
944
|
|
|
|
|
|
|
|
945
|
|
|
|
|
|
|
If the first argument names a sub-module, the processing is passed to the sub-module. |
946
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
=item * |
948
|
|
|
|
|
|
|
|
949
|
|
|
|
|
|
|
If the first argument does not match anything, then the default action is called, if specified, |
950
|
|
|
|
|
|
|
otherwise a 404 is returned to the user. |
951
|
|
|
|
|
|
|
|
952
|
|
|
|
|
|
|
=item * |
953
|
|
|
|
|
|
|
|
954
|
|
|
|
|
|
|
If there are no arguments, and the client was not requesting JSON, the viewport is executed. |
955
|
|
|
|
|
|
|
|
956
|
|
|
|
|
|
|
=item * |
957
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
Else, content is called, and its return value is passed to render_data. |
959
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
=back |
961
|
|
|
|
|
|
|
|
962
|
|
|
|
|
|
|
=cut |
963
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
sub controller_dispatch { |
965
|
52
|
|
|
52
|
1
|
137
|
my ($self, $opt, @subargs)= @_; |
966
|
52
|
|
|
|
|
112
|
my $c = $self->c; |
967
|
|
|
|
|
|
|
|
968
|
|
|
|
|
|
|
# We're doing this because its the cleanest way to expose the currently dispatching module to |
969
|
|
|
|
|
|
|
# other Catalyst Components, such as the view. We needed this specifically to add the literal |
970
|
|
|
|
|
|
|
# sql default_value handling (i.e. default column values like \'current_timestamp'). |
971
|
52
|
|
|
|
|
132
|
$c->stash->{'RAPIDAPP_DISPATCH_MODULE'} = $self; |
972
|
|
|
|
|
|
|
|
973
|
52
|
100
|
100
|
|
|
4511
|
return $self->Module($opt)->Controller($self->c,@subargs) |
|
|
|
66
|
|
|
|
|
974
|
|
|
|
|
|
|
if ($opt && !$self->has_action($opt) && $self->_load_module($opt)); |
975
|
|
|
|
|
|
|
|
976
|
12
|
100
|
66
|
|
|
270
|
return $self->process_action($opt,@subargs) |
977
|
|
|
|
|
|
|
if ($opt && $self->has_action($opt)); |
978
|
|
|
|
|
|
|
|
979
|
3
|
50
|
|
|
|
85
|
return $self->process_action($self->default_action,@_) |
980
|
|
|
|
|
|
|
if (defined $self->default_action); |
981
|
|
|
|
|
|
|
|
982
|
3
|
|
|
|
|
10
|
my $ct= $self->c->stash->{requestContentType}; |
983
|
|
|
|
|
|
|
|
984
|
|
|
|
|
|
|
# if there were unprocessed arguments which were not an action, and there was no default action, generate a 404 |
985
|
|
|
|
|
|
|
# UPDATE: unless new 'accept_subargs' attr is true (see attribute declaration above) |
986
|
3
|
50
|
33
|
|
|
250
|
if (defined $opt && !$self->accept_subargs) { |
|
|
100
|
66
|
|
|
|
|
987
|
|
|
|
|
|
|
# Handle the special case of browser requests for 'favicon.ico' (#57) |
988
|
0
|
0
|
0
|
|
|
0
|
return $c->redispatch_public_path( |
989
|
|
|
|
|
|
|
$c->default_favicon_url |
990
|
|
|
|
|
|
|
) if ($opt eq 'favicon.ico' && !$c->is_ra_ajax_req); |
991
|
|
|
|
|
|
|
|
992
|
0
|
0
|
|
|
|
0
|
$self->c->log->debug(join('',"--> ",RED,BOLD,"unknown action: $opt",CLEAR)) if ($self->c->debug); |
993
|
0
|
|
|
|
|
0
|
$c->stash->{template} = 'rapidapp/http-404.html'; |
994
|
0
|
|
|
|
|
0
|
$c->stash->{current_view} = 'RapidApp::Template'; |
995
|
0
|
|
|
|
|
0
|
$c->res->status(404); |
996
|
0
|
|
|
|
|
0
|
return $c->detach; |
997
|
|
|
|
|
|
|
} |
998
|
|
|
|
|
|
|
# -- |
999
|
|
|
|
|
|
|
# TODO: this is the last remaining logic from the old "web1" stuff (see the v0.996xx branch for |
1000
|
|
|
|
|
|
|
# the last state of that code before it was unfactored) |
1001
|
|
|
|
|
|
|
# |
1002
|
|
|
|
|
|
|
# this needs to be merged with the next, newer codeblock (render_viewport stuff...) |
1003
|
|
|
|
|
|
|
elsif ($self->auto_viewport && !$self->c->is_ra_ajax_req) { |
1004
|
1
|
50
|
|
|
|
77
|
$self->c->log->debug("--> " . GREEN . BOLD . "[auto_viewport_content]" . CLEAR . ". (no action)") |
1005
|
|
|
|
|
|
|
if($self->c->debug); |
1006
|
1
|
|
|
|
|
7
|
return $self->viewport; |
1007
|
|
|
|
|
|
|
} |
1008
|
|
|
|
|
|
|
# -- |
1009
|
|
|
|
|
|
|
else { |
1010
|
2
|
50
|
|
|
|
15
|
if(my $ret = $self->_maybe_render_viewport) { |
1011
|
0
|
|
|
|
|
0
|
return $ret; |
1012
|
|
|
|
|
|
|
} |
1013
|
|
|
|
|
|
|
else { |
1014
|
|
|
|
|
|
|
## --- |
1015
|
|
|
|
|
|
|
## detect direct browser GET requests (i.e. not from the ExtJS client) |
1016
|
|
|
|
|
|
|
## and redirect them back to the #! hashnav path |
1017
|
2
|
|
|
|
|
149
|
$self->auto_hashnav_redirect_current; |
1018
|
|
|
|
|
|
|
# --- |
1019
|
2
|
50
|
|
|
|
9
|
$self->c->log->debug("--> " . GREEN . BOLD . "[content]" . CLEAR . ". (no action)") |
1020
|
|
|
|
|
|
|
if($self->c->debug); |
1021
|
2
|
|
|
|
|
25
|
return $self->render_data($self->content); |
1022
|
|
|
|
|
|
|
} |
1023
|
|
|
|
|
|
|
} |
1024
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
} |
1026
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
sub _maybe_render_viewport { |
1029
|
11
|
|
|
11
|
|
25
|
my $self = shift; |
1030
|
|
|
|
|
|
|
|
1031
|
11
|
50
|
|
|
|
31
|
my $rdr_vp = $self->c->stash->{render_viewport} or return 0; |
1032
|
|
|
|
|
|
|
|
1033
|
0
|
0
|
0
|
|
|
0
|
if($rdr_vp && $rdr_vp eq 'printview' && $self->can('printview')) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1034
|
0
|
|
|
|
|
0
|
return $self->printview; |
1035
|
|
|
|
|
|
|
} |
1036
|
|
|
|
|
|
|
elsif($rdr_vp && $rdr_vp eq 'navable' && $self->can('navable')) { |
1037
|
0
|
|
|
|
|
0
|
return $self->navable; |
1038
|
|
|
|
|
|
|
} |
1039
|
|
|
|
|
|
|
elsif($rdr_vp && $self->can('viewport')) { |
1040
|
0
|
|
|
|
|
0
|
return $self->viewport; |
1041
|
|
|
|
|
|
|
} |
1042
|
|
|
|
|
|
|
} |
1043
|
|
|
|
|
|
|
|
1044
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
# This call happens via local method so subclasses are able to override |
1046
|
|
|
|
|
|
|
sub auto_hashnav_redirect_current { |
1047
|
2
|
|
|
2
|
0
|
5
|
my $self = shift; |
1048
|
2
|
|
|
|
|
9
|
$self->c->auto_hashnav_redirect_current |
1049
|
|
|
|
|
|
|
} |
1050
|
|
|
|
|
|
|
|
1051
|
|
|
|
|
|
|
|
1052
|
|
|
|
|
|
|
|
1053
|
|
|
|
|
|
|
=head2 process_action( $actionName, [optional @args] ) |
1054
|
|
|
|
|
|
|
|
1055
|
|
|
|
|
|
|
This routine handles the execution of a selected action. The action must exist. |
1056
|
|
|
|
|
|
|
For actions that map to coderefs, the coderef is executed. |
1057
|
|
|
|
|
|
|
For actions that map to strings, a method of that name is called on $self. |
1058
|
|
|
|
|
|
|
|
1059
|
|
|
|
|
|
|
=cut |
1060
|
|
|
|
|
|
|
sub process_action { |
1061
|
9
|
|
|
9
|
1
|
26
|
my $self = shift; |
1062
|
9
|
|
|
|
|
27
|
my ( $opt, @args ) = @_; |
1063
|
|
|
|
|
|
|
|
1064
|
9
|
50
|
|
|
|
35
|
die "No action specified" unless ($opt); |
1065
|
|
|
|
|
|
|
|
1066
|
9
|
50
|
|
|
|
29
|
$self->c->log->debug('--> ' . |
1067
|
|
|
|
|
|
|
GREEN.BOLD . ref($self) . CLEAR . ' ' . |
1068
|
|
|
|
|
|
|
GREEN . "action{ " . $opt . " }" . CLEAR . ' ' . |
1069
|
|
|
|
|
|
|
GREEN . join('/',@args) . CLEAR |
1070
|
|
|
|
|
|
|
) if ($self->c->debug); |
1071
|
|
|
|
|
|
|
|
1072
|
9
|
50
|
|
|
|
302
|
my $coderef = $self->get_action($opt) or die "No action named $opt"; |
1073
|
|
|
|
|
|
|
|
1074
|
9
|
50
|
|
|
|
51
|
if(my $ret = $self->_maybe_render_viewport) { |
1075
|
0
|
|
|
|
|
0
|
return $ret; |
1076
|
|
|
|
|
|
|
} |
1077
|
|
|
|
|
|
|
|
1078
|
|
|
|
|
|
|
# If $coderef is not actually a coderef, we assume its a string representing an |
1079
|
|
|
|
|
|
|
# object method and we call it directly: |
1080
|
9
|
50
|
|
|
|
587
|
return $self->render_data( |
1081
|
|
|
|
|
|
|
ref($coderef) eq 'CODE' ? |
1082
|
|
|
|
|
|
|
$coderef->($self,@args) : |
1083
|
|
|
|
|
|
|
$self->$coderef(@args) |
1084
|
|
|
|
|
|
|
); |
1085
|
|
|
|
|
|
|
} |
1086
|
|
|
|
|
|
|
|
1087
|
|
|
|
|
|
|
=head2 render_data( $data ) |
1088
|
|
|
|
|
|
|
|
1089
|
|
|
|
|
|
|
This is a very DWIM sort of routine that takes its parameter (likely the return value of |
1090
|
|
|
|
|
|
|
content or an action) and picks an appropriate view for it, possibly ignoring it altogether. |
1091
|
|
|
|
|
|
|
|
1092
|
|
|
|
|
|
|
=over |
1093
|
|
|
|
|
|
|
|
1094
|
|
|
|
|
|
|
=item * |
1095
|
|
|
|
|
|
|
|
1096
|
|
|
|
|
|
|
If the action generated a body, no view is needed, and the parameter is ignored. |
1097
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
=item * |
1099
|
|
|
|
|
|
|
|
1100
|
|
|
|
|
|
|
If the action chose its own view, no further processing is done, and the parameter is returned. |
1101
|
|
|
|
|
|
|
|
1102
|
|
|
|
|
|
|
=item * |
1103
|
|
|
|
|
|
|
|
1104
|
|
|
|
|
|
|
If the controller is configured to render json (the default) and the parameter isn't blacklisted |
1105
|
|
|
|
|
|
|
in no_json_ref_types, and the parameter isn't a plain string, the RapidApp::JSON view is chosen. |
1106
|
|
|
|
|
|
|
The parameter is returned (as-is) to get passed back to TopController who passes it to the view. |
1107
|
|
|
|
|
|
|
|
1108
|
|
|
|
|
|
|
=item * |
1109
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
Else, the data is treated as an explicit string for the body. The body is assigned, and returned. |
1111
|
|
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
=back |
1113
|
|
|
|
|
|
|
|
1114
|
|
|
|
|
|
|
=cut |
1115
|
|
|
|
|
|
|
sub render_data { |
1116
|
11
|
|
|
11
|
1
|
38
|
my ($self, $data)= @_; |
1117
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
#$self->c->log->debug(Dumper($data)); |
1119
|
|
|
|
|
|
|
|
1120
|
|
|
|
|
|
|
# do nothing if the body has been set |
1121
|
11
|
50
|
33
|
|
|
43
|
if (defined $self->c->response->body && length $self->c->response->body) { |
1122
|
0
|
|
|
|
|
0
|
$self->c->log->debug("(body set by user)"); |
1123
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
# check for the condition that will cause a "Wide character in syswrite" and give a better error message |
1125
|
0
|
0
|
|
|
|
0
|
if (utf8::is_utf8($self->c->response->body)) { |
1126
|
0
|
0
|
|
|
|
0
|
$self->c->response->content_type =~ /^text|xml$|javascript$|JSON$/ |
1127
|
|
|
|
|
|
|
or $self->c->log->warn("Controller ".(ref $self)." returned unicode text but isn't using a \"text\" content type!"); |
1128
|
|
|
|
|
|
|
} |
1129
|
0
|
|
|
|
|
0
|
return undef; |
1130
|
|
|
|
|
|
|
} |
1131
|
|
|
|
|
|
|
|
1132
|
|
|
|
|
|
|
# do nothing if the view has been configured |
1133
|
11
|
50
|
33
|
|
|
426
|
if (defined $self->c->stash->{current_view} || defined $self->c->stash->{current_view_instance}) { |
1134
|
0
|
|
|
|
|
0
|
$self->c->log->debug("(view set by user)"); |
1135
|
0
|
|
|
|
|
0
|
return $data; |
1136
|
|
|
|
|
|
|
} |
1137
|
|
|
|
|
|
|
|
1138
|
|
|
|
|
|
|
# if we want auto-json rendering, use the JSON view |
1139
|
11
|
50
|
33
|
|
|
908
|
if ($self->render_as_json && ref($data) && !defined $self->no_json_ref_types->{ref($data)}) { |
|
|
|
33
|
|
|
|
|
1140
|
11
|
|
|
|
|
31
|
$self->c->stash->{current_view} = 'RapidApp::JSON'; |
1141
|
11
|
|
|
|
|
1006
|
return $data; |
1142
|
|
|
|
|
|
|
} |
1143
|
|
|
|
|
|
|
# else set the body directly and use no view |
1144
|
|
|
|
|
|
|
else { |
1145
|
0
|
|
|
|
|
|
$self->c->response->header('Cache-Control' => 'no-cache'); |
1146
|
0
|
|
|
|
|
|
return $self->c->response->body( $data ); |
1147
|
|
|
|
|
|
|
} |
1148
|
|
|
|
|
|
|
} |
1149
|
|
|
|
|
|
|
|
1150
|
0
|
|
|
0
|
0
|
|
sub set_response_warning { (shift)->c->set_response_warning(@_) } |
1151
|
|
|
|
|
|
|
|
1152
|
|
|
|
|
|
|
|
1153
|
|
|
|
|
|
|
# if response_callback_scoped is true when set_response_callback is called, the |
1154
|
|
|
|
|
|
|
# function will be called with the scope (this reference) of the Ext.data.Connection |
1155
|
|
|
|
|
|
|
# object that initiated the Ajax request (Ext.Ajax.request) and this.response will |
1156
|
|
|
|
|
|
|
# also contain the response object; This is false by default because setting the |
1157
|
|
|
|
|
|
|
# scope breaks many functions, and this is usually not needed (the only reason to |
1158
|
|
|
|
|
|
|
# turn this on would be if you need to examine the specific request/response) |
1159
|
|
|
|
|
|
|
has 'response_callback_scoped' => ( |
1160
|
|
|
|
|
|
|
is => 'rw', |
1161
|
|
|
|
|
|
|
traits => [ 'RapidApp::Role::PerRequestBuildDefReset' ], |
1162
|
|
|
|
|
|
|
default => 0 |
1163
|
|
|
|
|
|
|
); |
1164
|
|
|
|
|
|
|
|
1165
|
|
|
|
|
|
|
=head2 set_response_callback |
1166
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
examples |
1168
|
|
|
|
|
|
|
|
1169
|
|
|
|
|
|
|
$self->set_response_callback( 'Ext.ux.MyFunc' ); |
1170
|
|
|
|
|
|
|
|
1171
|
|
|
|
|
|
|
$self->set_response_callback( alert => 'foo!' ); |
1172
|
|
|
|
|
|
|
|
1173
|
|
|
|
|
|
|
$self->set_response_callback( 'Ext.Msg.alert' => ( 'A message!!', 'this is awesome!!' ) ); |
1174
|
|
|
|
|
|
|
|
1175
|
|
|
|
|
|
|
my $func = RapidApp::JSONFunc->new( |
1176
|
|
|
|
|
|
|
raw => 1, |
1177
|
|
|
|
|
|
|
func => 'function(){ console.log("anon!!"); console.dir(this.response); }' |
1178
|
|
|
|
|
|
|
); |
1179
|
|
|
|
|
|
|
$self->response_callback_scoped(1); |
1180
|
|
|
|
|
|
|
$self->set_response_callback( |
1181
|
|
|
|
|
|
|
$func => ( "arg1",{ key_in_arg2 => 'blah!!!' },'arg3',\1 ) |
1182
|
|
|
|
|
|
|
); |
1183
|
|
|
|
|
|
|
|
1184
|
|
|
|
|
|
|
=cut |
1185
|
|
|
|
|
|
|
|
1186
|
|
|
|
|
|
|
# when calling set_response_callback the JS function specified will be |
1187
|
|
|
|
|
|
|
# called after the request is completed successfully |
1188
|
|
|
|
|
|
|
sub set_response_callback { |
1189
|
0
|
|
|
0
|
1
|
|
my ($self, $func, @args) = @_; |
1190
|
|
|
|
|
|
|
|
1191
|
0
|
|
|
|
|
|
my $data = {}; |
1192
|
0
|
0
|
|
|
|
|
$data->{arguments} = [ @args ] if (scalar @args > 0); |
1193
|
|
|
|
|
|
|
|
1194
|
0
|
0
|
|
|
|
|
if(ref($func) eq 'RapidApp::JSONFunc') { |
1195
|
0
|
0
|
|
|
|
|
die "only 'raw' RapidApp::JSONFunc objects are supported" unless ($func->raw); |
1196
|
0
|
|
|
|
|
|
$data->{anonfunc} = $func; |
1197
|
|
|
|
|
|
|
} |
1198
|
|
|
|
|
|
|
else { |
1199
|
0
|
|
|
|
|
|
$data->{func} = $func; |
1200
|
|
|
|
|
|
|
} |
1201
|
|
|
|
|
|
|
|
1202
|
0
|
0
|
|
|
|
|
$data->{scoped} = \1 if ($self->response_callback_scoped); |
1203
|
|
|
|
|
|
|
|
1204
|
0
|
|
|
|
|
|
return $self->c->response->header( 'X-RapidApp-Callback' => $self->json->encode($data) ); |
1205
|
|
|
|
|
|
|
} |
1206
|
|
|
|
|
|
|
|
1207
|
|
|
|
|
|
|
|
1208
|
|
|
|
|
|
|
has 'response_server_events' => ( |
1209
|
|
|
|
|
|
|
is => 'ro', |
1210
|
|
|
|
|
|
|
isa => 'ArrayRef[Str]', |
1211
|
|
|
|
|
|
|
traits => [ 'Array' ], |
1212
|
|
|
|
|
|
|
default => sub {[]}, |
1213
|
|
|
|
|
|
|
handles => { |
1214
|
|
|
|
|
|
|
add_response_server_events => 'push', |
1215
|
|
|
|
|
|
|
all_response_server_events => 'uniq' |
1216
|
|
|
|
|
|
|
} |
1217
|
|
|
|
|
|
|
); |
1218
|
|
|
|
|
|
|
after 'add_response_server_events' => sub { |
1219
|
|
|
|
|
|
|
my $self = shift; |
1220
|
|
|
|
|
|
|
$self->c->response->header( |
1221
|
|
|
|
|
|
|
'X-RapidApp-ServerEvents' => $self->json->encode([ $self->all_response_server_events ]) |
1222
|
|
|
|
|
|
|
); |
1223
|
|
|
|
|
|
|
}; |
1224
|
|
|
|
|
|
|
|
1225
|
|
|
|
|
|
|
|
1226
|
6
|
|
|
6
|
|
59
|
no Moose; |
|
6
|
|
|
|
|
15
|
|
|
6
|
|
|
|
|
62
|
|
1227
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
1228
|
|
|
|
|
|
|
|
1229
|
|
|
|
|
|
|
1; |
1230
|
|
|
|
|
|
|
|
1231
|
|
|
|
|
|
|
__END__ |
1232
|
|
|
|
|
|
|
|
1233
|
|
|
|
|
|
|
=head1 NAME |
1234
|
|
|
|
|
|
|
|
1235
|
|
|
|
|
|
|
RapidApp::Module - Base class for RapidApp Modules |
1236
|
|
|
|
|
|
|
|
1237
|
|
|
|
|
|
|
=head1 SYNOPSIS |
1238
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
package MyApp::Module::MyModule; |
1240
|
|
|
|
|
|
|
use Moose; |
1241
|
|
|
|
|
|
|
extends 'RapidApp::Module'; |
1242
|
|
|
|
|
|
|
|
1243
|
|
|
|
|
|
|
=head1 DESCRIPTION |
1244
|
|
|
|
|
|
|
|
1245
|
|
|
|
|
|
|
This is the base class for all RapidApp Modules. Documentation still TDB... |
1246
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
=head1 SEE ALSO |
1248
|
|
|
|
|
|
|
|
1249
|
|
|
|
|
|
|
=over |
1250
|
|
|
|
|
|
|
|
1251
|
|
|
|
|
|
|
=item * |
1252
|
|
|
|
|
|
|
|
1253
|
|
|
|
|
|
|
L<RapidApp::Manual::Modules> |
1254
|
|
|
|
|
|
|
|
1255
|
|
|
|
|
|
|
=back |
1256
|
|
|
|
|
|
|
|
1257
|
|
|
|
|
|
|
=head1 AUTHOR |
1258
|
|
|
|
|
|
|
|
1259
|
|
|
|
|
|
|
Henry Van Styn <vanstyn@cpan.org> |
1260
|
|
|
|
|
|
|
|
1261
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
1262
|
|
|
|
|
|
|
|
1263
|
|
|
|
|
|
|
This software is copyright (c) 2013 by IntelliTree Solutions llc. |
1264
|
|
|
|
|
|
|
|
1265
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
1266
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
1267
|
|
|
|
|
|
|
|
1268
|
|
|
|
|
|
|
=cut |
1269
|
|
|
|
|
|
|
|