line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Form::Factory::Action; |
2
|
|
|
|
|
|
|
$Form::Factory::Action::VERSION = '0.022'; |
3
|
1
|
|
|
1
|
|
4
|
use Moose::Role; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
7
|
|
4
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
2126
|
use Carp (); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
13
|
|
6
|
1
|
|
|
1
|
|
337
|
use Form::Factory::Feature::Functional; |
|
1
|
|
|
|
|
277
|
|
|
1
|
|
|
|
|
38
|
|
7
|
1
|
|
|
1
|
|
516
|
use Form::Factory::Result::Gathered; |
|
1
|
|
|
|
|
263
|
|
|
1
|
|
|
|
|
36
|
|
8
|
1
|
|
|
1
|
|
509
|
use Form::Factory::Result::Single; |
|
1
|
|
|
|
|
274
|
|
|
1
|
|
|
|
|
1783
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
#requires qw( run ); |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# ABSTRACT: Role implemented by actions |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
has form_interface => ( |
16
|
|
|
|
|
|
|
is => 'ro', |
17
|
|
|
|
|
|
|
does => 'Form::Factory::Interface', |
18
|
|
|
|
|
|
|
required => 1, |
19
|
|
|
|
|
|
|
); |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
has globals => ( |
23
|
|
|
|
|
|
|
is => 'ro', |
24
|
|
|
|
|
|
|
isa => 'HashRef[Str]', |
25
|
|
|
|
|
|
|
required => 1, |
26
|
|
|
|
|
|
|
default => sub { {} }, |
27
|
|
|
|
|
|
|
); |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
has results => ( |
31
|
|
|
|
|
|
|
is => 'rw', |
32
|
|
|
|
|
|
|
isa => 'Form::Factory::Result', |
33
|
|
|
|
|
|
|
required => 1, |
34
|
|
|
|
|
|
|
lazy => 1, |
35
|
|
|
|
|
|
|
default => sub { Form::Factory::Result::Gathered->new }, |
36
|
|
|
|
|
|
|
handles => [ qw( |
37
|
|
|
|
|
|
|
is_valid is_success is_failure |
38
|
|
|
|
|
|
|
is_validated is_outcome_known |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
all_messages regular_messages field_messages |
41
|
|
|
|
|
|
|
info_messages warning_messages error_messages |
42
|
|
|
|
|
|
|
regular_info_messages regular_warning_messages regular_error_messages |
43
|
|
|
|
|
|
|
field_info_messages field_warning_messages field_error_messages |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
content |
46
|
|
|
|
|
|
|
) ], |
47
|
|
|
|
|
|
|
); |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
has result => ( |
51
|
|
|
|
|
|
|
is => 'rw', |
52
|
|
|
|
|
|
|
isa => 'Form::Factory::Result::Single', |
53
|
|
|
|
|
|
|
required => 1, |
54
|
|
|
|
|
|
|
lazy => 1, |
55
|
|
|
|
|
|
|
default => sub { Form::Factory::Result::Single->new }, |
56
|
|
|
|
|
|
|
handles => [ qw( |
57
|
|
|
|
|
|
|
success failure |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
add_message |
60
|
|
|
|
|
|
|
info warning error |
61
|
|
|
|
|
|
|
field_info field_warning field_error |
62
|
|
|
|
|
|
|
) ], |
63
|
|
|
|
|
|
|
); |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
has features => ( |
67
|
|
|
|
|
|
|
is => 'ro', |
68
|
|
|
|
|
|
|
isa => 'ArrayRef', |
69
|
|
|
|
|
|
|
required => 1, |
70
|
|
|
|
|
|
|
lazy => 1, |
71
|
|
|
|
|
|
|
initializer => '_init_features', |
72
|
|
|
|
|
|
|
default => sub { [] }, |
73
|
|
|
|
|
|
|
); |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub _meta_features { |
76
|
14
|
|
|
14
|
|
27
|
my $self = shift; |
77
|
14
|
|
|
|
|
53
|
my $all_features = $self->meta->get_all_features; |
78
|
|
|
|
|
|
|
|
79
|
14
|
|
|
|
|
24
|
my @features; |
80
|
14
|
|
|
|
|
50
|
for my $feature_name (keys %$all_features) { |
81
|
7
|
|
|
|
|
14
|
my $feature_options = $all_features->{ $feature_name }; |
82
|
7
|
|
|
|
|
32
|
my $feature_class = Form::Factory->feature_class($feature_name); |
83
|
|
|
|
|
|
|
|
84
|
7
|
|
|
|
|
286
|
my $feature = $feature_class->new( |
85
|
|
|
|
|
|
|
%$feature_options, |
86
|
|
|
|
|
|
|
action => $self, |
87
|
|
|
|
|
|
|
); |
88
|
7
|
|
|
|
|
17
|
push @features, $feature; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
14
|
|
|
|
|
50
|
return \@features; |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub _init_features { |
95
|
14
|
|
|
14
|
|
728
|
my ($self, $features, $set, $attr) = @_; |
96
|
14
|
|
|
|
|
48
|
push @$features, @{ $self->_meta_features }; |
|
14
|
|
|
|
|
49
|
|
97
|
14
|
|
|
|
|
53
|
$set->($features); |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
has controls => ( |
102
|
|
|
|
|
|
|
is => 'ro', |
103
|
|
|
|
|
|
|
isa => 'HashRef', |
104
|
|
|
|
|
|
|
required => 1, |
105
|
|
|
|
|
|
|
lazy => 1, |
106
|
|
|
|
|
|
|
builder => '_build_controls', |
107
|
|
|
|
|
|
|
); |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub _build_controls { |
110
|
14
|
|
|
14
|
|
32
|
my $self = shift; |
111
|
14
|
|
|
|
|
505
|
my $interface = $self->form_interface; |
112
|
14
|
|
|
|
|
406
|
my $features = $self->features; |
113
|
|
|
|
|
|
|
|
114
|
14
|
|
|
|
|
24
|
my %controls; |
115
|
14
|
|
|
|
|
61
|
my @meta_controls = $self->meta->get_controls; |
116
|
14
|
|
|
|
|
167
|
for my $meta_control (@meta_controls) { |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
# Construct any deferred options |
119
|
75
|
|
|
|
|
72
|
my %options = %{ $meta_control->options }; |
|
75
|
|
|
|
|
2840
|
|
120
|
75
|
|
|
|
|
178
|
OPTION: for my $key (keys %options) { |
121
|
27
|
|
|
|
|
40
|
my $value = $options{$key}; |
122
|
|
|
|
|
|
|
|
123
|
27
|
100
|
|
|
|
118
|
next OPTION unless blessed $value; |
124
|
1
|
50
|
|
|
|
11
|
next OPTION unless $value->isa('Form::Factory::Processor::DeferredValue'); |
125
|
|
|
|
|
|
|
|
126
|
1
|
|
|
|
|
34
|
$options{$key} = $value->code->($self, $key); |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# Build the control constructor arguments |
130
|
75
|
|
|
|
|
236
|
my $control_name = $meta_control->name; |
131
|
75
|
100
|
|
|
|
2651
|
my %control_args = ( |
132
|
|
|
|
|
|
|
control => $meta_control->control, |
133
|
|
|
|
|
|
|
options => { |
134
|
|
|
|
|
|
|
name => $control_name, |
135
|
|
|
|
|
|
|
action => $self, |
136
|
|
|
|
|
|
|
($meta_control->has_documentation |
137
|
|
|
|
|
|
|
? (documentation => $meta_control->documentation) : ()), |
138
|
|
|
|
|
|
|
%options, |
139
|
|
|
|
|
|
|
}, |
140
|
|
|
|
|
|
|
); |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# Let any BuildControl features modify the constructor arguments |
143
|
75
|
|
|
|
|
1327
|
my %feature_classes; |
144
|
75
|
|
|
|
|
2532
|
my $meta_features = $meta_control->features; |
145
|
75
|
|
|
|
|
179
|
for my $feature_name (keys %$meta_features) { |
146
|
46
|
|
|
|
|
894
|
my $feature_class = Form::Factory->control_feature_class($feature_name); |
147
|
46
|
|
|
|
|
150
|
$feature_classes{$feature_name} = $feature_class; |
148
|
|
|
|
|
|
|
|
149
|
46
|
100
|
|
|
|
333
|
next unless $feature_class->does('Form::Factory::Feature::Role::BuildControl'); |
150
|
|
|
|
|
|
|
|
151
|
1
|
|
|
|
|
257
|
$feature_class->build_control( |
152
|
|
|
|
|
|
|
$meta_features->{$feature_name}, $self, $control_name, \%control_args |
153
|
|
|
|
|
|
|
); |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
# Construct the control |
157
|
75
|
|
|
|
|
1799
|
my $control = $interface->new_control( |
158
|
|
|
|
|
|
|
$control_args{control} => $control_args{options}, |
159
|
|
|
|
|
|
|
); |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# Construct and attach the features for the control |
162
|
75
|
|
|
|
|
90
|
my @init_control_features; |
163
|
75
|
|
|
|
|
200
|
for my $feature_name (keys %$meta_features) { |
164
|
46
|
|
|
|
|
819
|
my $feature_class = $feature_classes{$feature_name}; |
165
|
|
|
|
|
|
|
|
166
|
46
|
|
|
|
|
1969
|
my $feature = $feature_class->new( |
167
|
46
|
|
|
|
|
46
|
%{ $meta_features->{$feature_name} }, |
168
|
|
|
|
|
|
|
action => $self, |
169
|
|
|
|
|
|
|
control => $control, |
170
|
|
|
|
|
|
|
); |
171
|
46
|
|
|
|
|
1940
|
push @$features, $feature; |
172
|
46
|
|
|
|
|
51
|
push @{ $control->features }, $feature; |
|
46
|
|
|
|
|
1490
|
|
173
|
|
|
|
|
|
|
|
174
|
46
|
100
|
|
|
|
129
|
push @init_control_features, $feature |
175
|
|
|
|
|
|
|
if $feature->does('Form::Factory::Feature::Role::InitializeControl'); |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# Have InitializeControl features work on the constructed control |
179
|
75
|
|
|
|
|
1892
|
for my $feature (@init_control_features) { |
180
|
8
|
|
|
|
|
36
|
$feature->initialize_control; |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# Add the control to the list |
184
|
75
|
|
|
|
|
566
|
$controls{ $meta_control->name } = $control; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
14
|
|
|
|
|
503
|
return \%controls; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
sub stash { |
192
|
0
|
|
|
0
|
1
|
0
|
my ($self, $moniker) = @_; |
193
|
|
|
|
|
|
|
|
194
|
0
|
|
|
|
|
0
|
my $controls = $self->controls; |
195
|
0
|
|
|
|
|
0
|
my %controls; |
196
|
0
|
|
|
|
|
0
|
for my $control_name (keys %$controls) { |
197
|
0
|
|
|
|
|
0
|
my $control = $controls->{ $control_name }; |
198
|
0
|
|
|
|
|
0
|
$controls{$control_name}{value} = $control->value; |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
|
201
|
0
|
|
|
|
|
0
|
my %stash = ( |
202
|
|
|
|
|
|
|
globals => $self->globals, |
203
|
|
|
|
|
|
|
controls => \%controls, |
204
|
|
|
|
|
|
|
results => $self->results, |
205
|
|
|
|
|
|
|
result => $self->result, |
206
|
|
|
|
|
|
|
); |
207
|
|
|
|
|
|
|
|
208
|
0
|
|
|
|
|
0
|
$self->form_interface->stash($moniker => \%stash); |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub unstash { |
213
|
0
|
|
|
0
|
1
|
0
|
my ($self, $moniker) = @_; |
214
|
|
|
|
|
|
|
|
215
|
0
|
|
|
|
|
0
|
my $stash = $self->form_interface->unstash($moniker); |
216
|
0
|
0
|
|
|
|
0
|
return unless defined $stash; |
217
|
|
|
|
|
|
|
|
218
|
0
|
|
0
|
|
|
0
|
my $globals = $stash->{globals} || {}; |
219
|
0
|
|
|
|
|
0
|
for my $key (keys %$globals) { |
220
|
0
|
|
|
|
|
0
|
$self->globals->{$key} = $globals->{$key}; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
0
|
|
|
|
|
0
|
my $controls = $self->controls; |
224
|
0
|
|
0
|
|
|
0
|
my $controls_state = $stash->{controls} || {}; |
225
|
0
|
|
|
|
|
0
|
for my $control_name (keys %$controls) { |
226
|
0
|
|
|
|
|
0
|
my $state = $controls_state->{$control_name}; |
227
|
0
|
|
|
|
|
0
|
my $control = $controls->{$control_name}; |
228
|
0
|
|
|
|
|
0
|
eval { $control->value($state->{value}) }; |
|
0
|
|
|
|
|
0
|
|
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
0
|
|
0
|
|
|
0
|
$self->results($stash->{results} || Form::Factory::Result::Gathered->new); |
232
|
0
|
|
0
|
|
|
0
|
$self->result($stash->{result} || Form::Factory::Result::Single->new); |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
sub clear { |
237
|
21
|
|
|
21
|
1
|
45674
|
my ($self) = @_; |
238
|
|
|
|
|
|
|
|
239
|
21
|
|
|
|
|
48
|
%{ $self->globals } = (); |
|
21
|
|
|
|
|
646
|
|
240
|
|
|
|
|
|
|
|
241
|
21
|
|
|
|
|
612
|
my $controls = $self->controls; |
242
|
21
|
|
|
|
|
137
|
for my $control_name (keys %$controls) { |
243
|
141
|
|
|
|
|
138
|
my $control = $controls->{ $control_name }; |
244
|
141
|
|
|
|
|
199
|
delete $control->{value}; |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
|
247
|
21
|
|
|
|
|
648
|
$self->results->clear_all; |
248
|
21
|
|
|
|
|
624
|
$self->result(Form::Factory::Result::Single->new); |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
sub render { |
253
|
1
|
|
|
1
|
1
|
1409
|
my $self = shift; |
254
|
1
|
|
|
|
|
2
|
my %params = @_; |
255
|
0
|
|
|
|
|
0
|
my @names = defined $params{controls} ? @{ delete $params{controls} } |
|
8
|
|
|
|
|
38
|
|
256
|
1
|
50
|
|
|
|
12
|
: map { $_->name } |
257
|
|
|
|
|
|
|
$self->meta->get_controls |
258
|
|
|
|
|
|
|
; |
259
|
|
|
|
|
|
|
|
260
|
1
|
|
|
|
|
34
|
$params{results} = $self->results; |
261
|
|
|
|
|
|
|
|
262
|
1
|
|
|
|
|
26
|
my $controls = $self->controls; |
263
|
1
|
|
|
|
|
36
|
$self->form_interface->render_control($controls->{$_}, %params) for @names; |
264
|
1
|
|
|
|
|
39
|
return; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
sub setup_and_render { |
269
|
0
|
|
|
0
|
1
|
0
|
my ($self, %options) = @_; |
270
|
|
|
|
|
|
|
|
271
|
0
|
|
|
|
|
0
|
$self->unstash($options{moniker}); |
272
|
0
|
0
|
|
|
|
0
|
my %globals = %{ $options{globals} || {} }; |
|
0
|
|
|
|
|
0
|
|
273
|
0
|
|
|
|
|
0
|
for my $key (keys %globals) { |
274
|
0
|
|
|
|
|
0
|
$self->globals->{$key} = $globals{$key}; |
275
|
|
|
|
|
|
|
} |
276
|
0
|
|
|
|
|
0
|
$self->render(%options); |
277
|
0
|
|
|
|
|
0
|
$self->results->clear_all; |
278
|
0
|
|
|
|
|
0
|
$self->stash($options{moniker}); |
279
|
|
|
|
|
|
|
|
280
|
0
|
|
|
|
|
0
|
return; |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
sub render_control { |
285
|
1
|
|
|
1
|
1
|
4494
|
my ($self, $name, $options, %params) = @_; |
286
|
|
|
|
|
|
|
|
287
|
1
|
50
|
|
|
|
2
|
my %options = %{ $options || {} }; |
|
1
|
|
|
|
|
8
|
|
288
|
1
|
|
|
|
|
4
|
$options{action} = $self; |
289
|
|
|
|
|
|
|
|
290
|
1
|
|
|
|
|
29
|
$params{results} = $self->results; |
291
|
|
|
|
|
|
|
|
292
|
1
|
|
|
|
|
28
|
my $interface = $self->form_interface; |
293
|
1
|
|
|
|
|
9
|
my $control = $interface->new_control($name => \%options); |
294
|
|
|
|
|
|
|
|
295
|
1
|
|
|
|
|
9
|
$interface->render_control($control, %params); |
296
|
|
|
|
|
|
|
|
297
|
1
|
|
|
|
|
7
|
return $control; |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
sub consume { |
302
|
36
|
|
|
36
|
1
|
46840
|
my $self = shift; |
303
|
36
|
|
|
|
|
120
|
my %params = @_; |
304
|
15
|
|
|
|
|
58
|
my @names = defined $params{controls} ? @{ delete $params{controls} } |
|
125
|
|
|
|
|
349
|
|
305
|
36
|
100
|
|
|
|
224
|
: map { $_->name } |
306
|
|
|
|
|
|
|
$self->meta->get_controls |
307
|
|
|
|
|
|
|
; |
308
|
|
|
|
|
|
|
|
309
|
36
|
|
|
|
|
1257
|
my $controls = $self->controls; |
310
|
36
|
|
|
|
|
1111
|
$self->form_interface->consume_control($controls->{$_}, %params) for @names; |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
sub consume_control { |
315
|
2
|
|
|
2
|
1
|
4309
|
my ($self, $name, $options, %params) = @_; |
316
|
|
|
|
|
|
|
|
317
|
2
|
50
|
|
|
|
3
|
my %options = %{ $options || {} }; |
|
2
|
|
|
|
|
11
|
|
318
|
2
|
|
|
|
|
5
|
$options{action} = $self; |
319
|
|
|
|
|
|
|
|
320
|
2
|
|
|
|
|
56
|
$params{results} = $self->results; |
321
|
|
|
|
|
|
|
|
322
|
2
|
|
|
|
|
53
|
my $interface = $self->form_interface; |
323
|
2
|
|
|
|
|
11
|
my $control = $interface->new_control($name => \%options); |
324
|
|
|
|
|
|
|
|
325
|
2
|
|
|
|
|
15
|
$interface->consume_control($control, %params); |
326
|
|
|
|
|
|
|
|
327
|
2
|
|
|
|
|
8
|
return $control; |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
{ |
332
|
|
|
|
|
|
|
sub _run_features { |
333
|
82
|
|
|
82
|
|
107
|
my $self = shift; |
334
|
82
|
|
|
|
|
129
|
my $method = shift; |
335
|
82
|
|
|
|
|
153
|
my %params = @_; |
336
|
82
|
|
|
|
|
2823
|
my $features = $self->features; |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
# Only run the requested control-specific features |
339
|
82
|
100
|
|
|
|
245
|
if (defined $params{controls}) { |
340
|
30
|
|
|
|
|
38
|
my %names = map { $_ => 1 } @{ $params{controls} }; |
|
30
|
|
|
|
|
92
|
|
|
30
|
|
|
|
|
61
|
|
341
|
|
|
|
|
|
|
|
342
|
30
|
|
|
|
|
51
|
for my $feature (@$features) { |
343
|
210
|
50
|
|
|
|
3436
|
next unless $feature->does('Form::Factory::Feature::Role::Control'); |
344
|
210
|
100
|
|
|
|
6382
|
next unless $feature->does( |
345
|
|
|
|
|
|
|
Form::Factory::_class_name_from_name('Feature::Role', $method) |
346
|
|
|
|
|
|
|
); |
347
|
90
|
100
|
|
|
|
6007
|
next unless $names{ $feature->control->name }; |
348
|
|
|
|
|
|
|
|
349
|
15
|
|
|
|
|
79
|
$feature->$method; |
350
|
|
|
|
|
|
|
} |
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
# Run all features now |
354
|
|
|
|
|
|
|
else { |
355
|
52
|
|
|
|
|
170
|
for my $feature (@$features) { |
356
|
104
|
100
|
|
|
|
3211
|
next unless $feature->does( |
357
|
|
|
|
|
|
|
Form::Factory::_class_name_from_name('Feature::Role', $method) |
358
|
|
|
|
|
|
|
); |
359
|
|
|
|
|
|
|
|
360
|
51
|
|
|
|
|
2092
|
$feature->$method; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
sub clean { |
367
|
36
|
|
|
36
|
1
|
195
|
my $self = shift; |
368
|
36
|
|
|
|
|
155
|
$self->_run_features(clean => @_); |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
sub check { |
373
|
36
|
|
|
36
|
1
|
1656
|
my $self = shift; |
374
|
36
|
|
|
|
|
98
|
$self->_run_features(check => @_); |
375
|
|
|
|
|
|
|
|
376
|
36
|
|
|
|
|
292
|
$self->gather_results; |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
sub process { |
381
|
7
|
|
|
7
|
1
|
12
|
my $self = shift; |
382
|
7
|
100
|
|
|
|
39
|
return unless $self->is_valid; |
383
|
|
|
|
|
|
|
|
384
|
5
|
|
|
|
|
30
|
$self->set_attributes_from_controls; |
385
|
|
|
|
|
|
|
|
386
|
5
|
|
|
|
|
1204
|
$self->_run_features('pre_process'); |
387
|
5
|
|
|
|
|
83
|
$self->run; |
388
|
5
|
|
|
|
|
13
|
$self->_run_features('post_process'); |
389
|
|
|
|
|
|
|
|
390
|
5
|
|
|
|
|
77
|
$self->gather_results; |
391
|
|
|
|
|
|
|
|
392
|
5
|
|
|
|
|
29
|
my @errors = $self->error_messages; |
393
|
5
|
|
|
|
|
155
|
$self->result->is_success(@errors == 0); |
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
sub consume_and_clean_and_check_and_process { |
398
|
7
|
|
|
7
|
1
|
13632
|
my $self = shift; |
399
|
7
|
|
|
|
|
34
|
$self->consume(@_); |
400
|
7
|
|
|
|
|
37
|
$self->clean; |
401
|
7
|
|
|
|
|
116
|
$self->check; |
402
|
7
|
|
|
|
|
35
|
$self->process; |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
sub set_attribute_from_control { |
407
|
0
|
|
|
0
|
1
|
0
|
my ($self, $name) = @_; |
408
|
0
|
|
|
|
|
0
|
my $meta = $self->meta; |
409
|
|
|
|
|
|
|
|
410
|
0
|
|
|
|
|
0
|
my $control = $self->control->{$name}; |
411
|
0
|
|
|
|
|
0
|
my $attribute = $meta->find_attribute_by_name($name); |
412
|
0
|
|
|
|
|
0
|
$control->set_attribute_value($self, $attribute); |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
sub set_attributes_from_controls { |
417
|
5
|
|
|
5
|
1
|
6
|
my $self = shift; |
418
|
5
|
|
|
|
|
28
|
my $meta = $self->meta; |
419
|
|
|
|
|
|
|
|
420
|
5
|
|
|
|
|
252
|
my $controls = $self->controls; |
421
|
5
|
|
|
|
|
29
|
while (my ($name, $control) = each %$controls) { |
422
|
21
|
|
|
|
|
5671
|
my $attribute = $meta->find_attribute_by_name($name); |
423
|
21
|
50
|
|
|
|
829
|
Carp::croak("attribute for control $name not found on $self") |
424
|
|
|
|
|
|
|
unless defined $attribute; |
425
|
21
|
|
|
|
|
79
|
$control->set_attribute_value($self, $attribute); |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
sub gather_results { |
431
|
41
|
|
|
41
|
1
|
74
|
my $self = shift; |
432
|
41
|
|
|
|
|
1323
|
my $controls = $self->controls; |
433
|
157
|
|
|
|
|
5607
|
$self->results->gather_results( |
434
|
|
|
|
|
|
|
$self->result, |
435
|
41
|
|
|
|
|
1335
|
map { $_->result } @{ $self->features } |
|
41
|
|
|
|
|
1352
|
|
436
|
|
|
|
|
|
|
); |
437
|
|
|
|
|
|
|
} |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
1; |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
__END__ |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
=pod |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
=encoding UTF-8 |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
=head1 NAME |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
Form::Factory::Action - Role implemented by actions |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
=head1 VERSION |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
version 0.022 |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
=head1 DESCRIPTION |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
This is the role implemented by all form actions. Rather than doing so directly, you should use L<Form::Factory::Processor> as demonstrated in the L</SYNOPSIS>. |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
=head2 SYNOPSIS |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
package MyApp::Action::Foo; |
463
|
|
|
|
|
|
|
use Form::Factory::Processor; |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
has_control bar => ( |
466
|
|
|
|
|
|
|
type => 'text', |
467
|
|
|
|
|
|
|
); |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
sub run { |
470
|
|
|
|
|
|
|
my $self = shift; |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
# Do something... |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
All form actions have the following attributes. |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
=head2 form_interface |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
This is the L<Form::Factory::Interface> that constructed this action. If you need to get at the implementation directly for some reason, here it is. This is mostly used by the action itself when calling the L</render> and L</consume> methods. |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
=head2 globals |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
This is a hash of extra parameters to keep with the form. Normally, these are saved with a call to L</stash> and recovered with a call to L</unstash>. |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
=head2 results |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
This is a L<Form::Factory::Result::Gathered> object that tracks the general success, failure, messages, and output from the execution of this action. |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
Actions delegate a number of methods to this object. See L</RESULTS>. |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
=head2 result |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
This is a L<Form::Factory::Result::Single> used to record general outcome. |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
Actions delegate a number of methods to this object. See L</RESULTS>. |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
=head2 features |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
This is a list of L<Form::Factory::Feature> objects used to modify the object. This will always contain the features that are attached to the class itself. Additional features may be added here. |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
=head2 controls |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
This is a hash of controls attached to this action. For every C<has_control> line in the action class, there should be a matching control in this hash. |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
=head1 METHODS |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
=head2 stash |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
$action->stash($moniker); |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
Given a C<$moniker> (a key under which to store the information related to this form), this will stash the form's stashable information under that name using the L<Form::Factory::Stasher> associated with the L</form_interface>. |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
The globals, values of controls, and the results are stashed. This allows those values to be recovered across requests or between process calls or whatever the implementation requires. |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
=head2 unstash |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
$action->unstash($moniker); |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
Given a C<$moniker> previously named in a call to L</stash>, it restores the previously stashed state. This is a no-op if nothing is stashed under this moniker. |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=head2 clear |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
This method clears the stashable state of the action. |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
=head2 render |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
$action->render(%options); |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
Renders the form using the associated L</form_interface>. You may specify the following options: |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
=over |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
=item controls |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
This is a list of control names to render. If not given, all controls will be rendered. |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=back |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
Any other options will be passed on to the L<Form::Factory::Interface/render_control> method. |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
=head2 setup_and_render |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
$self->setup_and_render(%options); |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
This performs the most common steps to prepare for a render and render: |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
=over |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
=item 1 |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
Unstashes from the given C<moniker>. |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
=item 2 |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
Adds the given C<globals> to the globals. |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
=item 3 |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
Renders the action. |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
=item 4 |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
Clears the results. |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
=item 5 |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
Stashes what we've done back into the given C<moniker>. |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
=back |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
=head2 render_control |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
my $control = $action->render_control($name, \%options); |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
Creates and renders a one time control. This is mostly useful for attaching buttons to a form. The control is not added to the list of controls on the action and will not be processed later. |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
This method returns the control object that was just rendered. |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
=head2 consume |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
$action->consume(%options); |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
This consumes any input from user and places it into the controls of the form. You may pass the following options: |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
=over |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
=item controls |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
This is a list of names of controls to consume. Any not listed here will not be consumed. If this option is missing, all control values are consumed. |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
=back |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
Any additional options will be passed to the L<Form::Factory::Interface/consume_control> method call. |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
=head2 consume_control |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
my $control = $action->consume_control($name, \%options, %params); |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
Consumes the value of a one time control. This is useful for testing to see if a form submitted using a one-time control has been submitted or not. |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
This method returns the control object that was consumed. |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
=head2 clean |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
$action->clean(%options); |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
Takes the values consumed from the user and cleans them up. For example, if you allow users to type in a phone number, this can be used to clear out any unwanted or incorrect punctuation and format the phone number properly. |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
This method runs through all the requested L<Form::Factory::Feature> objects in L</features> and runs the L<Form::Factory::Feature/clean> method for each. |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
The following options are used: |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
=over |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
=item controls |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
This is the list of controls to clean. If not given, all features will be run. If given, only the control-features (those implementing L<Form::Factory::Feature::Role::Control> attached to the named controls) will be run. Any form-features or unlisted control-features will not be run. |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
=back |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
=head2 check |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
$action->check(%options); |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
The C<check> method is responsible for verifying the correctness of the input. It assumes that L</clean> has already run. |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
It runs the L<Form::Factory::Feature/check> method of all the selected L</features> attached to the action. It also sets the C<is_valid> flag to true if no errors have been recored yet or to false if they have. |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
The following options are used: |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
=over |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
=item controls |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
This is the list of controls to check. If not given, all features will be run. If given, only the control-features (those implementing L<Form::Factory::Feature::Role::Control> attached to the named controls) will be run. Any form-features or unlisted control-features will not be run. |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
=back |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
=head2 process |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
$action->process; |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
This does nothing if the action did not validate. |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
In the case the action is valid, this will use L</set_attributes_from_controls> to copy the control values to the action attributes, run the L<Form::Factory::Feature/pre_process> methods for all form-features and control-features, call the L</run> method, run the L<Form::Factory::Feature/post_process> methods for all form-features and control-features, and set the C<is_success> flag to true if no errors are recorded or false if there are. |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
=head2 consume_and_clean_and_check_and_process |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
This is a shortcut for taking all the usual workflow actions in a single call: |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
$action->consume(@_); |
654
|
|
|
|
|
|
|
$action->clean; |
655
|
|
|
|
|
|
|
$action->check |
656
|
|
|
|
|
|
|
$action->process; |
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
=head1 ROLE METHODS |
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
This method must be implemented by any action implementation. |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
=head2 run |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
This is the method that actually does the work. It takes no arguments and is expected to return nothing. You should draw your input from the action attributes (not the controls) and report your results to L</result>. |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
=head1 HELPER METHODS |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
These methods are primarily intended for internal use. |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
=head2 set_attribute_from_control |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
Given the name of a control, this will copy the current value in the control to the attribute. |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
=head2 set_attributes_from_controls |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
This method is used by L</process> to copy the values out of the controls into the form action attributes. This assumes that such a copy will work because the L</clean> and L</check> phases should have already run and passed without error. |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
=head2 gather_results |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
Gathers results for all the associated L</controls> and L</result> into L</results>. This is called just before deciding if the action has validated correctly or if the action has succeeded. |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
=head1 RESULTS |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
Actions are tied closely to L<Form::Factory::Result>s. As such, a number of methods are delegated to result classes. |
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
The following methods are delegated to L</results> in L<Form::Factory::Result::Gathered>. |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
=over |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
=item is_valid |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
=item is_success |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
=item is_failure |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
=item is_validated |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
=item is_outcome_known |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
=item all_messages |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
=item regular_messages |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
=item field_messages |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
=item info_messages |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
=item warning_messages |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
=item error_messages |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
=item regular_info_messages |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
=item regular_warning_messages |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
=item regular_error_messages |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
=item field_info_messages |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
=item field_warning_messages |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
=item field_error_messages |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
=item content |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
=back |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
These methods are delegated to L<result> in L<Form::Factory::Result::Single>. |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
=over |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
=item success |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
=item failure |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
=item add_message |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
=item info |
739
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
=item warning |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
=item error |
743
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
=item field_info |
745
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
=item field_warning |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
=item field_error |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
=back |
751
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
=head1 WORKFLOW |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
=head2 TYPICAL CASE |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
The action workflow typically goes like this. There are two phases. |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
=head3 PHASE 1: SHOW THE FORM |
759
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
Phase 1 is responsible for showing the form to the user. This phase might be skipped altogether in situations where automatic processing is taking place where the robot doing the work already knows what inputs are expected for the action. However, typically, you do something like this: |
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
my $action = $interface->new_action('Foo'); |
763
|
|
|
|
|
|
|
$action->unstash('foo'); |
764
|
|
|
|
|
|
|
$action->render; |
765
|
|
|
|
|
|
|
$action->render_control(button => { |
766
|
|
|
|
|
|
|
name => 'submit', |
767
|
|
|
|
|
|
|
label => 'Do It', |
768
|
|
|
|
|
|
|
}); |
769
|
|
|
|
|
|
|
$action->stash('foo'); |
770
|
|
|
|
|
|
|
|
771
|
|
|
|
|
|
|
This tells the interface that you want to prepare a form object for class "Foo." |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
The call to L</unstash> then pulls in any state saved from the user's prior entry. This will cause any errors that occurred on a previous validation or process execution to show up (assuming that your interface does that work for you). This also means that any previously stashed values entered should reappear in the form so that a failure to save or something won't cause the field information to be lost forever. |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
The call to L</render> causes all of the controls of the form to be rendered for input. |
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
The call to L</render_control> causes a button to appear in the form. |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
The call to L</stash> returns the form's stashable information back to the stash, since L</unstash> typically removes it. |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
=head3 PHASE 2: PROCESSING THE INPUT |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
Once the user has submitted the form, you will want to process the input and perform the action. This typically looks like this: |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
my $action = $interface->new_action('Foo'); |
786
|
|
|
|
|
|
|
$action->unstash('foo'); |
787
|
|
|
|
|
|
|
$action->consume_and_clean_and_check_and_process( request => $q->Vars ); |
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
if ($action->is_valid and $action->is_success) { |
790
|
|
|
|
|
|
|
# Go on to the next thing |
791
|
|
|
|
|
|
|
} |
792
|
|
|
|
|
|
|
else { |
793
|
|
|
|
|
|
|
$action->stash('foo'); |
794
|
|
|
|
|
|
|
# Go render the form again and show the errors |
795
|
|
|
|
|
|
|
} |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
We request an instance of the form again and then call L</unstash> to recover any stashed setup. We then call the L</consume_and_clean_and_check_and_process> method, which will consume all the input. Here we use something that looks like a L<CGI> request for the source of input, but it should be whatever is appropriate to your environment and the L<Form::Factory::Interface> implementation used. |
798
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
At the end, we check to see if the action checked out and then that the L</run> method ran without problems. If so, we can show the success page or the record view or whatever is appropriate after filling this form. |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
If there are errors, we should perform the rendering action for L</PHASE 1: SHOW THE FORM> again after doing a L</stash> to make sure the information is ready to be recovered. |
802
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
=head2 VARATIONS |
804
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
=head3 PER-CONTROL CLEANING AND CHECKING |
806
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
Ajax or GUIs will generally want to give their feedback as early as possible. As such, whenever the user finishes entering a value or the application thinks that validation is needed, the app might perform: |
808
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
$action->check( controls => [ qw( some_control ) ] ); |
810
|
|
|
|
|
|
|
$action->clean( controls => [ qw( some_control ) ] ); |
811
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
unless ($action->is_valid) { |
813
|
|
|
|
|
|
|
# Report $action->results->error_messages |
814
|
|
|
|
|
|
|
} |
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
You will still run the steps above, but can do a check and clean on a subset of controls when you need to do so to give the user early feedback. |
817
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
=head1 AUTHOR |
819
|
|
|
|
|
|
|
|
820
|
|
|
|
|
|
|
Andrew Sterling Hanenkamp <hanenkamp@cpan.org> |
821
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
823
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
This software is copyright (c) 2015 by Qubling Software LLC. |
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
827
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
=cut |