line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package HTML::FormHandler; |
2
|
|
|
|
|
|
|
# ABSTRACT: HTML forms using Moose |
3
|
|
|
|
|
|
|
$HTML::FormHandler::VERSION = '0.40067'; |
4
|
141
|
|
|
141
|
|
260986
|
use Moose; |
|
141
|
|
|
|
|
646048
|
|
|
141
|
|
|
|
|
873
|
|
5
|
|
|
|
|
|
|
extends 'HTML::FormHandler::Base'; # to make some methods overridable by roles |
6
|
|
|
|
|
|
|
with 'HTML::FormHandler::Model', 'HTML::FormHandler::Fields', |
7
|
|
|
|
|
|
|
'HTML::FormHandler::BuildFields', |
8
|
|
|
|
|
|
|
'HTML::FormHandler::TraitFor::I18N'; |
9
|
|
|
|
|
|
|
with 'HTML::FormHandler::InitResult'; |
10
|
|
|
|
|
|
|
with 'HTML::FormHandler::Widget::ApplyRole'; |
11
|
|
|
|
|
|
|
with 'HTML::FormHandler::Traits'; |
12
|
|
|
|
|
|
|
with 'HTML::FormHandler::Blocks'; |
13
|
|
|
|
|
|
|
|
14
|
141
|
|
|
141
|
|
644328
|
use Carp; |
|
141
|
|
|
|
|
228
|
|
|
141
|
|
|
|
|
8365
|
|
15
|
141
|
|
|
141
|
|
578
|
use Class::MOP; |
|
141
|
|
|
|
|
170
|
|
|
141
|
|
|
|
|
2609
|
|
16
|
141
|
|
|
141
|
|
55167
|
use HTML::FormHandler::Result; |
|
141
|
|
|
|
|
436
|
|
|
141
|
|
|
|
|
6732
|
|
17
|
141
|
|
|
141
|
|
82153
|
use HTML::FormHandler::Field; |
|
141
|
|
|
|
|
443
|
|
|
141
|
|
|
|
|
7883
|
|
18
|
141
|
|
|
141
|
|
980
|
use Try::Tiny; |
|
141
|
|
|
|
|
204
|
|
|
141
|
|
|
|
|
10515
|
|
19
|
141
|
|
|
141
|
|
96567
|
use MooseX::Types::LoadableClass qw/ LoadableClass /; |
|
141
|
|
|
|
|
9774917
|
|
|
141
|
|
|
|
|
829
|
|
20
|
141
|
|
|
141
|
|
147991
|
use namespace::autoclean; |
|
141
|
|
|
|
|
244
|
|
|
141
|
|
|
|
|
853
|
|
21
|
141
|
|
|
141
|
|
9238
|
use HTML::FormHandler::Merge ('merge'); |
|
141
|
|
|
|
|
220
|
|
|
141
|
|
|
|
|
7783
|
|
22
|
141
|
|
|
141
|
|
644
|
use Sub::Name; |
|
141
|
|
|
|
|
215
|
|
|
141
|
|
|
|
|
5361
|
|
23
|
141
|
|
|
141
|
|
594
|
use Data::Clone; |
|
141
|
|
|
|
|
200
|
|
|
141
|
|
|
|
|
5365
|
|
24
|
|
|
|
|
|
|
|
25
|
141
|
|
|
141
|
|
4808
|
use 5.008; |
|
141
|
|
|
|
|
626
|
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# for consistency in api with field nodes |
29
|
17319
|
|
|
17319
|
1
|
205323
|
sub form { shift } |
30
|
0
|
|
|
0
|
0
|
0
|
sub is_form { 1 } |
31
|
0
|
|
|
0
|
0
|
0
|
sub has_form { 1 } |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# Moose attributes |
34
|
|
|
|
|
|
|
has 'name' => ( |
35
|
|
|
|
|
|
|
isa => 'Str', |
36
|
|
|
|
|
|
|
is => 'rw', |
37
|
|
|
|
|
|
|
default => sub { return 'form' . int( rand 1000 ) } |
38
|
|
|
|
|
|
|
); |
39
|
4113
|
|
|
4113
|
0
|
6834
|
sub full_name { '' } |
40
|
10
|
|
|
10
|
0
|
17
|
sub full_accessor { '' } |
41
|
|
|
|
|
|
|
has 'parent' => ( is => 'rw' ); |
42
|
|
|
|
|
|
|
has 'result' => ( |
43
|
|
|
|
|
|
|
isa => 'HTML::FormHandler::Result', |
44
|
|
|
|
|
|
|
is => 'ro', |
45
|
|
|
|
|
|
|
writer => '_set_result', |
46
|
|
|
|
|
|
|
clearer => 'clear_result', |
47
|
|
|
|
|
|
|
lazy => 1, |
48
|
|
|
|
|
|
|
builder => 'build_result', |
49
|
|
|
|
|
|
|
predicate => 'has_result', |
50
|
|
|
|
|
|
|
handles => [ |
51
|
|
|
|
|
|
|
'input', '_set_input', '_clear_input', 'has_input', |
52
|
|
|
|
|
|
|
'value', '_set_value', '_clear_value', 'has_value', |
53
|
|
|
|
|
|
|
'add_result', 'results', 'validated', 'ran_validation', |
54
|
|
|
|
|
|
|
'is_valid', |
55
|
|
|
|
|
|
|
'form_errors', 'all_form_errors', 'push_form_errors', 'clear_form_errors', |
56
|
|
|
|
|
|
|
'has_form_errors', 'num_form_errors', |
57
|
|
|
|
|
|
|
], |
58
|
|
|
|
|
|
|
); |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
sub build_result { |
61
|
541
|
|
|
541
|
0
|
741
|
my $self = shift; |
62
|
541
|
|
|
|
|
814
|
my $result_class = 'HTML::FormHandler::Result'; |
63
|
541
|
50
|
|
|
|
12799
|
if ( $self->widget_form ) { |
64
|
541
|
|
|
|
|
13439
|
my $role = $self->get_widget_role( $self->widget_form, 'Form' ); |
65
|
541
|
|
|
|
|
23623
|
$result_class = $result_class->with_traits( $role ); |
66
|
|
|
|
|
|
|
} |
67
|
541
|
|
|
|
|
14473
|
my $result = $result_class->new( name => $self->name, form => $self ); |
68
|
541
|
|
|
|
|
426176
|
return $result; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
has 'index' => ( |
72
|
|
|
|
|
|
|
is => 'ro', isa => 'HashRef[HTML::FormHandler::Field]', traits => ['Hash'], |
73
|
|
|
|
|
|
|
default => sub {{}}, |
74
|
|
|
|
|
|
|
handles => { |
75
|
|
|
|
|
|
|
add_to_index => 'set', |
76
|
|
|
|
|
|
|
field_from_index => 'get', |
77
|
|
|
|
|
|
|
field_in_index => 'exists', |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
); |
80
|
|
|
|
|
|
|
has '_repeatable_fields' => ( is => 'rw', isa => 'ArrayRef', |
81
|
|
|
|
|
|
|
traits => ['Array'], default => sub {[]}, |
82
|
|
|
|
|
|
|
handles => { |
83
|
|
|
|
|
|
|
add_repeatable_field => 'push', |
84
|
|
|
|
|
|
|
has_repeatable_fields => 'count', |
85
|
|
|
|
|
|
|
all_repeatable_fields => 'elements', |
86
|
|
|
|
|
|
|
}, |
87
|
|
|
|
|
|
|
); |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
has 'field_traits' => ( is => 'ro', traits => ['Array'], isa => 'ArrayRef', |
90
|
|
|
|
|
|
|
default => sub {[]}, handles => { 'has_field_traits' => 'count' } ); |
91
|
|
|
|
|
|
|
has 'widget_name_space' => ( |
92
|
|
|
|
|
|
|
is => 'ro', |
93
|
|
|
|
|
|
|
isa => 'HFH::ArrayRefStr', |
94
|
|
|
|
|
|
|
traits => ['Array'], |
95
|
|
|
|
|
|
|
default => sub {[]}, |
96
|
|
|
|
|
|
|
coerce => 1, |
97
|
|
|
|
|
|
|
handles => { |
98
|
|
|
|
|
|
|
add_widget_name_space => 'push', |
99
|
|
|
|
|
|
|
}, |
100
|
|
|
|
|
|
|
); |
101
|
|
|
|
|
|
|
# it only really makes sense to set these before widget_form is applied in BUILD |
102
|
|
|
|
|
|
|
has 'widget_form' => ( is => 'ro', isa => 'Str', default => 'Simple', writer => 'set_widget_form' ); |
103
|
|
|
|
|
|
|
has 'widget_wrapper' => ( is => 'ro', isa => 'Str', default => 'Simple', writer => 'set_widget_wrapper' ); |
104
|
|
|
|
|
|
|
has 'do_form_wrapper' => ( is => 'rw', builder => 'build_do_form_wrapper' ); |
105
|
235
|
|
|
235
|
0
|
108364
|
sub build_do_form_wrapper { 0 } |
106
|
|
|
|
|
|
|
has 'no_widgets' => ( is => 'ro', isa => 'Bool' ); |
107
|
|
|
|
|
|
|
has 'no_preload' => ( is => 'ro', isa => 'Bool' ); |
108
|
|
|
|
|
|
|
has 'no_update' => ( is => 'rw', isa => 'Bool', clearer => 'clear_no_update' ); |
109
|
|
|
|
|
|
|
has 'active' => ( |
110
|
|
|
|
|
|
|
is => 'rw', |
111
|
|
|
|
|
|
|
traits => ['Array'], |
112
|
|
|
|
|
|
|
isa => 'ArrayRef[Str]', |
113
|
|
|
|
|
|
|
default => sub {[]}, |
114
|
|
|
|
|
|
|
handles => { |
115
|
|
|
|
|
|
|
add_active => 'push', |
116
|
|
|
|
|
|
|
has_active => 'count', |
117
|
|
|
|
|
|
|
clear_active => 'clear', |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
); |
120
|
|
|
|
|
|
|
has 'inactive' => ( |
121
|
|
|
|
|
|
|
is => 'rw', |
122
|
|
|
|
|
|
|
traits => ['Array'], |
123
|
|
|
|
|
|
|
isa => 'ArrayRef[Str]', |
124
|
|
|
|
|
|
|
default => sub {[]}, |
125
|
|
|
|
|
|
|
handles => { |
126
|
|
|
|
|
|
|
add_inactive => 'push', |
127
|
|
|
|
|
|
|
has_inactive => 'count', |
128
|
|
|
|
|
|
|
clear_inactive => 'clear', |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
); |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# object with which to initialize |
134
|
|
|
|
|
|
|
has 'init_object' => ( is => 'rw', clearer => 'clear_init_object' ); |
135
|
|
|
|
|
|
|
has 'update_field_list' => ( is => 'rw', |
136
|
|
|
|
|
|
|
isa => 'HashRef', |
137
|
|
|
|
|
|
|
default => sub {{}}, |
138
|
|
|
|
|
|
|
traits => ['Hash'], |
139
|
|
|
|
|
|
|
handles => { |
140
|
|
|
|
|
|
|
clear_update_field_list => 'clear', |
141
|
|
|
|
|
|
|
has_update_field_list => 'count', |
142
|
|
|
|
|
|
|
set_update_field_list => 'set', |
143
|
|
|
|
|
|
|
}, |
144
|
|
|
|
|
|
|
); |
145
|
|
|
|
|
|
|
has 'defaults' => ( is => 'rw', isa => 'HashRef', default => sub {{}}, traits => ['Hash'], |
146
|
|
|
|
|
|
|
handles => { has_defaults => 'count', clear_defaults => 'clear' }, |
147
|
|
|
|
|
|
|
); |
148
|
|
|
|
|
|
|
has 'use_defaults_over_obj' => ( is => 'rw', isa => 'Bool', clearer => 'clear_use_defaults_over_obj' ); |
149
|
|
|
|
|
|
|
has 'use_init_obj_over_item' => ( is => 'rw', isa => 'Bool', clearer => 'clear_use_init_obj_over_item' ); |
150
|
|
|
|
|
|
|
has 'use_init_obj_when_no_accessor_in_item' => ( is => 'rw', isa => 'Bool' ); |
151
|
|
|
|
|
|
|
has 'use_fields_for_input_without_param' => ( is => 'rw', isa => 'Bool' ); |
152
|
|
|
|
|
|
|
# flags |
153
|
|
|
|
|
|
|
has [ 'verbose', 'processed', 'did_init_obj' ] => ( isa => 'Bool', is => 'rw' ); |
154
|
|
|
|
|
|
|
has 'user_data' => ( isa => 'HashRef', is => 'rw' ); |
155
|
|
|
|
|
|
|
has 'ctx' => ( is => 'rw', weak_ref => 1, clearer => 'clear_ctx' ); |
156
|
|
|
|
|
|
|
has 'html_prefix' => ( isa => 'Bool', is => 'ro' ); |
157
|
|
|
|
|
|
|
has 'active_column' => ( isa => 'Str', is => 'ro' ); |
158
|
|
|
|
|
|
|
has 'http_method' => ( isa => 'Str', is => 'ro', default => 'post' ); |
159
|
|
|
|
|
|
|
has 'enctype' => ( is => 'rw', isa => 'Str' ); |
160
|
|
|
|
|
|
|
has 'error_message' => ( is => 'rw', predicate => 'has_error_message', clearer => 'clear_error_message' ); |
161
|
|
|
|
|
|
|
has 'success_message' => ( is => 'rw', predicate => 'has_success_message', clearer => 'clear_success_message' ); |
162
|
|
|
|
|
|
|
has 'info_message' => ( is => 'rw', predicate => 'has_info_message', clearer => 'clear_info_message' ); |
163
|
|
|
|
|
|
|
# deprecated |
164
|
|
|
|
|
|
|
has 'style' => ( isa => 'Str', is => 'rw' ); |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
has 'is_html5' => ( isa => 'Bool', is => 'ro', default => 0 ); |
167
|
|
|
|
|
|
|
# deprecated. use form_element_attr instead |
168
|
|
|
|
|
|
|
has 'html_attr' => ( is => 'rw', traits => ['Hash'], |
169
|
|
|
|
|
|
|
default => sub { {} }, handles => { has_html_attr => 'count', |
170
|
|
|
|
|
|
|
set_html_attr => 'set', delete_html_attr => 'delete' }, |
171
|
|
|
|
|
|
|
trigger => \&_html_attr_set, |
172
|
|
|
|
|
|
|
); |
173
|
|
|
|
|
|
|
sub _html_attr_set { |
174
|
0
|
|
|
0
|
|
0
|
my ( $self, $value ) = @_; |
175
|
0
|
|
|
|
|
0
|
my $class = delete $value->{class}; |
176
|
0
|
|
|
|
|
0
|
$self->form_element_attr($value); |
177
|
0
|
0
|
|
|
|
0
|
$self->add_form_element_class if $class; |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
{ |
181
|
|
|
|
|
|
|
# create the attributes and methods for |
182
|
|
|
|
|
|
|
# form_element_attr, build_form_element_attr, form_element_class, |
183
|
|
|
|
|
|
|
# form_wrapper_attr, build_form_wrapper_atrr, form_wrapper_class |
184
|
141
|
|
|
141
|
|
1019
|
no strict 'refs'; |
|
141
|
|
|
|
|
255
|
|
|
141
|
|
|
|
|
444807
|
|
185
|
|
|
|
|
|
|
foreach my $attr ('form_wrapper', 'form_element' ) { |
186
|
|
|
|
|
|
|
my $add_meth = "add_${attr}_class"; |
187
|
|
|
|
|
|
|
has "${attr}_attr" => ( is => 'rw', traits => ['Hash'], |
188
|
|
|
|
|
|
|
builder => "build_${attr}_attr", |
189
|
|
|
|
|
|
|
handles => { |
190
|
|
|
|
|
|
|
"has_${attr}_attr" => 'count', |
191
|
|
|
|
|
|
|
"get_${attr}_attr" => 'get', |
192
|
|
|
|
|
|
|
"set_${attr}_attr" => 'set', |
193
|
|
|
|
|
|
|
"delete_${attr}_attr" => 'delete', |
194
|
|
|
|
|
|
|
"exists_${attr}_attr" => 'exists', |
195
|
|
|
|
|
|
|
}, |
196
|
|
|
|
|
|
|
); |
197
|
|
|
|
|
|
|
# create builders for _attr |
198
|
|
|
|
|
|
|
my $attr_builder = __PACKAGE__ . "::build_${attr}_attr"; |
199
|
486
|
|
|
486
|
0
|
218458
|
*$attr_builder = subname $attr_builder, sub {{}}; |
|
|
|
|
486
|
0
|
|
|
200
|
|
|
|
|
|
|
# create the 'class' slots |
201
|
|
|
|
|
|
|
has "${attr}_class" => ( is => 'rw', isa => 'HFH::ArrayRefStr', |
202
|
|
|
|
|
|
|
traits => ['Array'], |
203
|
|
|
|
|
|
|
coerce => 1, |
204
|
|
|
|
|
|
|
builder => "build_${attr}_class", |
205
|
|
|
|
|
|
|
handles => { |
206
|
|
|
|
|
|
|
"has_${attr}_class" => 'count', |
207
|
|
|
|
|
|
|
"_add_${attr}_class" => 'push', |
208
|
|
|
|
|
|
|
}, |
209
|
|
|
|
|
|
|
); |
210
|
|
|
|
|
|
|
# create builders for classes |
211
|
|
|
|
|
|
|
my $class_builder = __PACKAGE__ . "::build_${attr}_class"; |
212
|
470
|
|
|
470
|
0
|
237279
|
*$class_builder = subname $class_builder, sub {[]}; |
|
|
|
|
470
|
0
|
|
|
213
|
|
|
|
|
|
|
# create wrapper for add_to_ to accept arrayref |
214
|
|
|
|
|
|
|
my $add_to_class = __PACKAGE__ . "::add_${attr}_class"; |
215
|
|
|
|
|
|
|
my $_add_meth = __PACKAGE__ . "::_add_${attr}_class"; |
216
|
|
|
|
|
|
|
# create add method that takes an arrayref |
217
|
0
|
0
|
|
0
|
0
|
0
|
*$add_to_class = subname $add_to_class, sub { shift->$_add_meth((ref $_[0] eq 'ARRAY' ? @{$_[0]} : @_)); } |
|
0
|
|
|
0
|
0
|
0
|
|
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
85
|
|
|
85
|
1
|
504
|
sub attributes { shift->form_element_attributes(@_) } |
222
|
|
|
|
|
|
|
sub form_element_attributes { |
223
|
85
|
|
|
85
|
0
|
151
|
my ( $self, $result ) = @_; |
224
|
85
|
|
66
|
|
|
443
|
$result ||= $self->result; |
225
|
85
|
|
|
|
|
179
|
my $attr = {}; |
226
|
85
|
|
|
|
|
1784
|
$attr->{id} = $self->name; |
227
|
85
|
100
|
|
|
|
2454
|
$attr->{action} = $self->action if $self->action; |
228
|
85
|
50
|
|
|
|
2278
|
$attr->{method} = $self->http_method if $self->http_method; |
229
|
85
|
50
|
|
|
|
2238
|
$attr->{enctype} = $self->enctype if $self->enctype; |
230
|
85
|
100
|
|
|
|
3048
|
$attr->{style} = $self->style if $self->style; |
231
|
85
|
|
|
|
|
301
|
$attr = {%$attr, %{$self->form_element_attr}}; |
|
85
|
|
|
|
|
2469
|
|
232
|
85
|
|
|
|
|
225
|
my $class = [@{$self->form_element_class}]; |
|
85
|
|
|
|
|
2318
|
|
233
|
85
|
100
|
|
|
|
270
|
$attr->{class} = $class if @$class; |
234
|
85
|
|
|
|
|
448
|
my $mod_attr = $self->html_attributes($self, 'form_element', $attr); |
235
|
85
|
50
|
|
|
|
771
|
return ref $mod_attr eq 'HASH' ? $mod_attr : $attr; |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
sub form_wrapper_attributes { |
238
|
15
|
|
|
15
|
0
|
29
|
my ( $self, $result ) = @_; |
239
|
15
|
|
33
|
|
|
140
|
$result ||= $self->result; |
240
|
15
|
|
|
|
|
23
|
my $attr = {%{$self->form_wrapper_attr}}; |
|
15
|
|
|
|
|
457
|
|
241
|
15
|
|
|
|
|
24
|
my $class = [@{$self->form_wrapper_class}]; |
|
15
|
|
|
|
|
450
|
|
242
|
15
|
100
|
|
|
|
56
|
$attr->{class} = $class if @$class; |
243
|
15
|
|
|
|
|
57
|
my $mod_attr = $self->html_attributes($self, 'form_wrapper', $attr); |
244
|
15
|
50
|
|
|
|
107
|
return ref $mod_attr eq 'HASH' ? $mod_attr : $attr; |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
sub html_attributes { |
248
|
1364
|
|
|
1364
|
0
|
1645
|
my ( $self, $obj, $type, $attrs, $result ) = @_; |
249
|
|
|
|
|
|
|
# deprecated 'field_html_attributes'; name changed, remove eventually |
250
|
1364
|
50
|
|
|
|
4104
|
if( $self->can('field_html_attributes') ) { |
251
|
0
|
|
|
|
|
0
|
$attrs = $self->field_html_attributes( $obj, $type, $attrs, $result ); |
252
|
|
|
|
|
|
|
} |
253
|
1364
|
|
|
|
|
2159
|
return $attrs; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
sub has_flag { |
257
|
2216
|
|
|
2216
|
0
|
3338
|
my ( $self, $flag_name ) = @_; |
258
|
2216
|
100
|
|
|
|
13803
|
return unless $self->can($flag_name); |
259
|
943
|
|
|
|
|
20687
|
return $self->$flag_name; |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
has 'form_tags' => ( |
263
|
|
|
|
|
|
|
traits => ['Hash'], |
264
|
|
|
|
|
|
|
isa => 'HashRef', |
265
|
|
|
|
|
|
|
is => 'ro', |
266
|
|
|
|
|
|
|
builder => 'build_form_tags', |
267
|
|
|
|
|
|
|
handles => { |
268
|
|
|
|
|
|
|
_get_tag => 'get', |
269
|
|
|
|
|
|
|
set_tag => 'set', |
270
|
|
|
|
|
|
|
tag_exists => 'exists', |
271
|
|
|
|
|
|
|
has_tag => 'exists', |
272
|
|
|
|
|
|
|
}, |
273
|
|
|
|
|
|
|
); |
274
|
233
|
|
|
233
|
0
|
123399
|
sub build_form_tags {{}} |
275
|
|
|
|
|
|
|
sub get_tag { |
276
|
655
|
|
|
655
|
0
|
775
|
my ( $self, $name ) = @_; |
277
|
655
|
100
|
|
|
|
18687
|
return '' unless $self->tag_exists($name); |
278
|
46
|
|
|
|
|
1269
|
my $tag = $self->_get_tag($name); |
279
|
46
|
50
|
|
|
|
113
|
return $self->$tag if ref $tag eq 'CODE'; |
280
|
46
|
50
|
|
|
|
208
|
return $tag unless $tag =~ /^%/; |
281
|
0
|
|
|
|
|
0
|
( my $block_name = $tag ) =~ s/^%//; |
282
|
0
|
0
|
0
|
|
|
0
|
return $self->form->block($block_name)->render |
283
|
|
|
|
|
|
|
if ( $self->form && $self->form->block_exists($block_name) ); |
284
|
0
|
|
|
|
|
0
|
return ''; |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
has 'for_js' => ( |
287
|
|
|
|
|
|
|
isa => 'HashRef', |
288
|
|
|
|
|
|
|
traits => ['Hash'], |
289
|
|
|
|
|
|
|
is => 'rw', |
290
|
|
|
|
|
|
|
default => sub { {} }, |
291
|
|
|
|
|
|
|
handles => { |
292
|
|
|
|
|
|
|
set_for_js => 'set', |
293
|
|
|
|
|
|
|
has_for_js => 'count', |
294
|
|
|
|
|
|
|
clear_for_js => 'clear', |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
); |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
has 'action' => ( is => 'rw' ); |
299
|
|
|
|
|
|
|
has 'posted' => ( is => 'rw', isa => 'Bool', clearer => 'clear_posted', predicate => 'has_posted' ); |
300
|
|
|
|
|
|
|
has 'params' => ( |
301
|
|
|
|
|
|
|
traits => ['Hash'], |
302
|
|
|
|
|
|
|
isa => 'HashRef', |
303
|
|
|
|
|
|
|
is => 'rw', |
304
|
|
|
|
|
|
|
default => sub { {} }, |
305
|
|
|
|
|
|
|
trigger => sub { shift->_munge_params(@_) }, |
306
|
|
|
|
|
|
|
handles => { |
307
|
|
|
|
|
|
|
set_param => 'set', |
308
|
|
|
|
|
|
|
get_param => 'get', |
309
|
|
|
|
|
|
|
clear_params => 'clear', |
310
|
|
|
|
|
|
|
has_params => 'count', |
311
|
|
|
|
|
|
|
}, |
312
|
|
|
|
|
|
|
); |
313
|
0
|
|
|
0
|
0
|
0
|
sub submitted { shift->has_params } |
314
|
|
|
|
|
|
|
has 'dependency' => ( isa => 'ArrayRef', is => 'rw' ); |
315
|
|
|
|
|
|
|
has '_required' => ( |
316
|
|
|
|
|
|
|
traits => ['Array'], |
317
|
|
|
|
|
|
|
isa => 'ArrayRef[HTML::FormHandler::Field]', |
318
|
|
|
|
|
|
|
is => 'rw', |
319
|
|
|
|
|
|
|
default => sub { [] }, |
320
|
|
|
|
|
|
|
handles => { |
321
|
|
|
|
|
|
|
clear_required => 'clear', |
322
|
|
|
|
|
|
|
add_required => 'push', |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
); |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
# these messages could apply to either fields or form |
327
|
|
|
|
|
|
|
has 'messages' => ( is => 'rw', |
328
|
|
|
|
|
|
|
isa => 'HashRef', |
329
|
|
|
|
|
|
|
traits => ['Hash'], |
330
|
|
|
|
|
|
|
builder => 'build_messages', |
331
|
|
|
|
|
|
|
handles => { |
332
|
|
|
|
|
|
|
'_get_form_message' => 'get', |
333
|
|
|
|
|
|
|
'_has_form_message' => 'exists', |
334
|
|
|
|
|
|
|
'set_message' => 'set', |
335
|
|
|
|
|
|
|
}, |
336
|
|
|
|
|
|
|
); |
337
|
245
|
|
|
245
|
0
|
126766
|
sub build_messages { {} } |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
my $class_messages = {}; |
340
|
|
|
|
|
|
|
sub get_class_messages { |
341
|
0
|
|
|
0
|
0
|
0
|
return $class_messages; |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
sub get_message { |
345
|
0
|
|
|
0
|
0
|
0
|
my ( $self, $msg ) = @_; |
346
|
0
|
0
|
|
|
|
0
|
return $self->_get_form_message($msg) if $self->_has_form_message($msg); |
347
|
0
|
|
|
|
|
0
|
return $self->get_class_messages->{$msg}; |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
sub all_messages { |
350
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
351
|
0
|
|
|
|
|
0
|
return { %{$self->get_class_messages}, %{$self->messages} }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
has 'params_class' => ( |
355
|
|
|
|
|
|
|
is => 'ro', |
356
|
|
|
|
|
|
|
isa => LoadableClass, |
357
|
|
|
|
|
|
|
coerce => 1, |
358
|
|
|
|
|
|
|
default => 'HTML::FormHandler::Params', |
359
|
|
|
|
|
|
|
); |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
has 'params_args' => ( is => 'ro', isa => 'ArrayRef' ); |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
sub BUILDARGS { |
364
|
246
|
|
|
246
|
1
|
2427
|
my $class = shift; |
365
|
|
|
|
|
|
|
|
366
|
246
|
50
|
66
|
|
|
1167
|
if ( scalar @_ == 1 && ref( $_[0]) ne 'HASH' ) { |
367
|
0
|
|
|
|
|
0
|
my $arg = $_[0]; |
368
|
0
|
0
|
|
|
|
0
|
return blessed($arg) ? { item => $arg } : { item_id => $arg }; |
369
|
|
|
|
|
|
|
} |
370
|
246
|
|
|
|
|
1568
|
return $class->SUPER::BUILDARGS(@_); |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
sub BUILD { |
374
|
246
|
|
|
246
|
0
|
712275
|
my $self = shift; |
375
|
|
|
|
|
|
|
|
376
|
246
|
|
|
|
|
1394
|
$self->before_build; # hook to allow customizing forms |
377
|
|
|
|
|
|
|
# HTML::FormHandler::Widget::Form::Simple is applied in Base |
378
|
246
|
100
|
66
|
|
|
7824
|
$self->apply_widget_role( $self, $self->widget_form, 'Form' ) |
379
|
|
|
|
|
|
|
unless ( $self->no_widgets || $self->widget_form eq 'Simple' ); |
380
|
246
|
|
|
|
|
69317
|
$self->_build_fields; # create the form fields (BuildFields.pm) |
381
|
243
|
100
|
66
|
|
|
9122
|
$self->build_active if $self->has_active || $self->has_inactive || $self->has_flag('is_wizard'); |
|
|
|
100
|
|
|
|
|
382
|
243
|
|
|
|
|
1259
|
$self->after_build; # hook for customizing |
383
|
243
|
50
|
33
|
|
|
6767
|
return if defined $self->item_id && !$self->item; |
384
|
|
|
|
|
|
|
# Load values from object (if any) |
385
|
|
|
|
|
|
|
# Would rather not load results at all here, but skipping it breaks |
386
|
|
|
|
|
|
|
# existing apps that perform certain actions between 'new' and 'process'. |
387
|
|
|
|
|
|
|
# Added fudge flag no_preload to enable skipping. |
388
|
|
|
|
|
|
|
# A well-behaved program that always does ->process shouldn't need this preloading. |
389
|
243
|
100
|
|
|
|
6297
|
unless( $self->no_preload ) { |
390
|
242
|
50
|
0
|
|
|
6669
|
if ( my $init_object = $self->use_init_obj_over_item ? |
|
|
100
|
100
|
|
|
|
|
391
|
|
|
|
|
|
|
($self->init_object || $self->item) : ( $self->item || $self->init_object ) ) { |
392
|
10
|
|
|
|
|
303
|
$self->_result_from_object( $self->result, $init_object ); |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
else { |
395
|
232
|
|
|
|
|
5897
|
$self->_result_from_fields( $self->result ); |
396
|
|
|
|
|
|
|
} |
397
|
|
|
|
|
|
|
} |
398
|
243
|
50
|
|
|
|
6961
|
$self->dump_fields if $self->verbose; |
399
|
243
|
|
|
|
|
1036
|
return; |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
245
|
0
|
|
sub before_build {} |
402
|
|
|
|
243
|
0
|
|
sub after_build {} |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
sub process { |
405
|
271
|
|
|
271
|
1
|
93435
|
my $self = shift; |
406
|
|
|
|
|
|
|
|
407
|
271
|
50
|
|
|
|
7877
|
warn "HFH: process ", $self->name, "\n" if $self->verbose; |
408
|
271
|
100
|
|
|
|
6801
|
$self->clear if $self->processed; |
409
|
271
|
|
|
|
|
1418
|
$self->setup_form(@_); |
410
|
271
|
100
|
|
|
|
6255
|
$self->validate_form if $self->posted; |
411
|
271
|
100
|
100
|
|
|
1584
|
$self->update_model if ( $self->validated && !$self->no_update ); |
412
|
271
|
100
|
100
|
|
|
1216
|
$self->after_update_model if ( $self->validated && !$self->no_update ); |
413
|
271
|
50
|
|
|
|
6164
|
$self->dump_fields if $self->verbose; |
414
|
271
|
|
|
|
|
6309
|
$self->processed(1); |
415
|
271
|
|
|
|
|
820
|
return $self->validated; |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
sub run { |
419
|
12
|
|
|
12
|
0
|
2406
|
my $self = shift; |
420
|
12
|
|
|
|
|
44
|
$self->setup_form(@_); |
421
|
12
|
100
|
|
|
|
289
|
$self->validate_form if $self->posted; |
422
|
12
|
100
|
66
|
|
|
51
|
$self->update_model if ( $self->validated && !$self->no_update );; |
423
|
12
|
|
|
|
|
252
|
my $result = $self->result; |
424
|
12
|
|
|
|
|
64
|
$self->clear; |
425
|
12
|
|
|
|
|
40
|
return $result; |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
sub after_update_model { |
429
|
96
|
|
|
96
|
0
|
172
|
my $self = shift; |
430
|
|
|
|
|
|
|
# This an attempt to reload the repeatable |
431
|
|
|
|
|
|
|
# relationships after the database is updated, so that we get the |
432
|
|
|
|
|
|
|
# primary keys of the repeatable elements. Otherwise, if a form |
433
|
|
|
|
|
|
|
# is re-presented, repeatable elements without primary keys may |
434
|
|
|
|
|
|
|
# be created again. There is no reliable way to connect up |
435
|
|
|
|
|
|
|
# existing repeatable elements with their db-created primary keys. |
436
|
96
|
100
|
100
|
|
|
3350
|
if ( $self->has_repeatable_fields && $self->item ) { |
437
|
2
|
|
|
|
|
74
|
foreach my $field ( $self->all_repeatable_fields ) { |
438
|
4
|
50
|
|
|
|
12
|
next unless $field->is_active; |
439
|
|
|
|
|
|
|
# Check to see if there are any repeatable subfields with |
440
|
|
|
|
|
|
|
# null primary keys, so we can skip reloading for the case |
441
|
|
|
|
|
|
|
# where all repeatables have primary keys. |
442
|
4
|
|
|
|
|
7
|
my $needs_reload = 0; |
443
|
4
|
|
|
|
|
102
|
foreach my $sub_field ( $field->fields ) { |
444
|
9
|
100
|
100
|
|
|
31
|
if ( $sub_field->has_flag('is_compound') && $sub_field->has_primary_key ) { |
445
|
1
|
|
|
|
|
2
|
foreach my $pk_field ( @{ $sub_field->primary_key } ) { |
|
1
|
|
|
|
|
30
|
|
446
|
1
|
50
|
|
|
|
8
|
$needs_reload++ unless $pk_field->fif; |
447
|
|
|
|
|
|
|
} |
448
|
1
|
50
|
|
|
|
5
|
last if $needs_reload; |
449
|
|
|
|
|
|
|
} |
450
|
|
|
|
|
|
|
} |
451
|
4
|
100
|
|
|
|
11
|
next unless $needs_reload; |
452
|
1
|
|
|
|
|
4
|
my @names = split( /\./, $field->full_name ); |
453
|
1
|
|
|
|
|
22
|
my $rep_item = $self->find_sub_item( $self->item, \@names ); |
454
|
|
|
|
|
|
|
# $rep_item is a single row or an array of rows or undef |
455
|
|
|
|
|
|
|
# If we found a database item for the repeatable, replace |
456
|
|
|
|
|
|
|
# the existing result with a result derived from the item. |
457
|
1
|
50
|
|
|
|
3
|
if ( ref $rep_item ) { |
458
|
1
|
|
|
|
|
23
|
my $parent = $field->parent; |
459
|
1
|
|
|
|
|
24
|
my $result = $field->result; |
460
|
1
|
|
|
|
|
5
|
$field->init_state; |
461
|
1
|
|
|
|
|
6
|
my $new_result = $field->_result_from_object( $result, $rep_item ); |
462
|
|
|
|
|
|
|
# find index of existing result |
463
|
1
|
|
|
3
|
|
23
|
my $index = $parent->result->find_result_index( sub { $_ == $result } ); |
|
3
|
|
|
|
|
94
|
|
464
|
|
|
|
|
|
|
# replace existing result with new result |
465
|
1
|
|
|
|
|
24
|
$parent->result->set_result_at_index( $index, $new_result ); |
466
|
|
|
|
|
|
|
} |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
} |
469
|
|
|
|
|
|
|
} |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
sub db_validate { |
473
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
474
|
0
|
|
|
|
|
0
|
my $fif = $self->fif; |
475
|
0
|
|
|
|
|
0
|
$self->process($fif); |
476
|
0
|
|
|
|
|
0
|
return $self->validated; |
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
sub clear { |
480
|
116
|
|
|
116
|
0
|
195
|
my $self = shift; |
481
|
116
|
|
|
|
|
752
|
$self->clear_data; |
482
|
116
|
|
|
|
|
3859
|
$self->clear_params; |
483
|
116
|
|
|
|
|
3133
|
$self->clear_posted; |
484
|
116
|
|
|
|
|
3341
|
$self->clear_item; |
485
|
116
|
|
|
|
|
3376
|
$self->clear_init_object; |
486
|
116
|
|
|
|
|
3233
|
$self->clear_ctx; |
487
|
116
|
|
|
|
|
2707
|
$self->processed(0); |
488
|
116
|
|
|
|
|
2769
|
$self->did_init_obj(0); |
489
|
116
|
|
|
|
|
3014
|
$self->clear_result; |
490
|
116
|
|
|
|
|
3735
|
$self->clear_use_defaults_over_obj; |
491
|
116
|
|
|
|
|
3657
|
$self->clear_use_init_obj_over_item; |
492
|
116
|
|
|
|
|
3374
|
$self->clear_no_update; |
493
|
116
|
|
|
|
|
3351
|
$self->clear_info_message; |
494
|
116
|
|
|
|
|
3504
|
$self->clear_for_js; |
495
|
|
|
|
|
|
|
} |
496
|
|
|
|
|
|
|
|
497
|
13
|
|
|
13
|
0
|
97
|
sub values { shift->value } |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
# deprecated? |
500
|
|
|
|
|
|
|
sub error_field_names { |
501
|
1
|
|
|
1
|
0
|
2
|
my $self = shift; |
502
|
1
|
|
|
|
|
4
|
my @error_fields = $self->error_fields; |
503
|
1
|
|
|
|
|
4
|
return map { $_->name } @error_fields; |
|
3
|
|
|
|
|
67
|
|
504
|
|
|
|
|
|
|
} |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
sub errors { |
507
|
8
|
|
|
8
|
1
|
202
|
my $self = shift; |
508
|
8
|
|
|
|
|
48
|
my @error_fields = $self->error_fields; |
509
|
8
|
|
|
|
|
67
|
my @errors = $self->all_form_errors; |
510
|
8
|
|
|
|
|
18
|
push @errors, map { $_->all_errors } @error_fields; |
|
13
|
|
|
|
|
82
|
|
511
|
8
|
|
|
|
|
32
|
return @errors; |
512
|
|
|
|
|
|
|
} |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
sub errors_by_id { |
515
|
1
|
|
|
1
|
0
|
2
|
my $self = shift; |
516
|
1
|
|
|
|
|
1
|
my %errors; |
517
|
1
|
|
|
|
|
7
|
$errors{$_->id} = [$_->all_errors] for $self->error_fields; |
518
|
1
|
|
|
|
|
5
|
return \%errors; |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
sub errors_by_name { |
522
|
1
|
|
|
1
|
0
|
1
|
my $self = shift; |
523
|
1
|
|
|
|
|
1
|
my %errors; |
524
|
1
|
|
|
|
|
4
|
$errors{$_->html_name} = [$_->all_errors] for $self->error_fields; |
525
|
1
|
|
|
|
|
4
|
return \%errors; |
526
|
|
|
|
|
|
|
} |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
sub build_errors { |
529
|
165
|
|
|
165
|
0
|
280
|
my $self = shift; |
530
|
|
|
|
|
|
|
# this puts the errors in the result |
531
|
165
|
|
|
|
|
243
|
foreach my $err_res (@{$self->result->error_results}) { |
|
165
|
|
|
|
|
3645
|
|
532
|
89
|
|
|
|
|
1912
|
$self->result->_push_errors($err_res->all_errors); |
533
|
|
|
|
|
|
|
} |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
sub uuid { |
537
|
0
|
|
|
0
|
0
|
0
|
my $form = shift; |
538
|
0
|
|
|
|
|
0
|
require Data::UUID; |
539
|
0
|
|
|
|
|
0
|
my $uuid = Data::UUID->new->create_str; |
540
|
0
|
|
|
|
|
0
|
return qq[<input type="hidden" name="form_uuid" value="$uuid">]; |
541
|
|
|
|
|
|
|
} |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
sub validate_form { |
544
|
165
|
|
|
165
|
0
|
331
|
my $self = shift; |
545
|
165
|
|
|
|
|
3802
|
my $params = $self->params; |
546
|
165
|
|
|
|
|
898
|
$self->_set_dependency; # set required dependencies |
547
|
165
|
|
|
|
|
964
|
$self->_fields_validate; |
548
|
165
|
|
|
|
|
871
|
$self->validate; # empty method for users |
549
|
165
|
|
|
|
|
1039
|
$self->validate_model; # model specific validation |
550
|
165
|
|
|
|
|
913
|
$self->fields_set_value; |
551
|
165
|
|
|
|
|
1328
|
$self->build_errors; # move errors to result |
552
|
165
|
|
|
|
|
859
|
$self->_clear_dependency; |
553
|
165
|
|
|
|
|
5641
|
$self->clear_posted; |
554
|
165
|
|
|
|
|
1168
|
$self->ran_validation(1); |
555
|
165
|
50
|
|
|
|
4107
|
$self->dump_validated if $self->verbose; |
556
|
165
|
|
|
|
|
1013
|
return $self->validated; |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
|
559
|
158
|
|
|
158
|
1
|
235
|
sub validate { 1 } |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
sub has_errors { |
562
|
19
|
|
|
19
|
0
|
875
|
my $self = shift; |
563
|
19
|
|
100
|
|
|
113
|
return $self->has_error_fields || $self->has_form_errors; |
564
|
|
|
|
|
|
|
} |
565
|
|
|
|
|
|
|
sub num_errors { |
566
|
6
|
|
|
6
|
0
|
348
|
my $self = shift; |
567
|
6
|
|
|
|
|
38
|
return $self->num_error_fields + $self->num_form_errors; |
568
|
|
|
|
|
|
|
} |
569
|
0
|
|
|
0
|
0
|
0
|
sub get_errors { shift->errors } |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
sub setup_form { |
572
|
283
|
|
|
283
|
0
|
660
|
my ( $self, @args ) = @_; |
573
|
283
|
100
|
|
|
|
1351
|
if ( @args == 1 ) { |
|
|
100
|
|
|
|
|
|
574
|
80
|
|
|
|
|
2109
|
$self->params( $args[0] ); |
575
|
|
|
|
|
|
|
} |
576
|
|
|
|
|
|
|
elsif ( @args > 1 ) { |
577
|
169
|
|
|
|
|
429
|
my $hashref = {@args}; |
578
|
169
|
|
|
|
|
282
|
while ( my ( $key, $value ) = each %{$hashref} ) { |
|
408
|
|
|
|
|
1458
|
|
579
|
239
|
50
|
|
|
|
1184
|
confess "invalid attribute '$key' passed to setup_form" |
580
|
|
|
|
|
|
|
unless $self->can($key); |
581
|
239
|
|
|
|
|
5966
|
$self->$key($value); |
582
|
|
|
|
|
|
|
} |
583
|
|
|
|
|
|
|
} |
584
|
283
|
50
|
66
|
|
|
7087
|
if ( $self->item_id && !$self->item ) { |
585
|
0
|
|
|
|
|
0
|
$self->item( $self->build_item ); |
586
|
|
|
|
|
|
|
} |
587
|
283
|
|
|
|
|
7977
|
$self->clear_result; |
588
|
283
|
|
|
|
|
1616
|
$self->set_active; |
589
|
283
|
|
|
|
|
1257
|
$self->update_fields; |
590
|
|
|
|
|
|
|
# initialization of Repeatable fields and Select options |
591
|
|
|
|
|
|
|
# will be done in _result_from_object when there's an initial object |
592
|
|
|
|
|
|
|
# in _result_from_input when there are params |
593
|
|
|
|
|
|
|
# and by _result_from_fields for empty forms |
594
|
283
|
100
|
100
|
|
|
8603
|
$self->posted(1) if ( $self->has_params && !$self->has_posted ); |
595
|
283
|
50
|
|
|
|
7232
|
if ( !$self->did_init_obj ) { |
596
|
283
|
100
|
33
|
|
|
6925
|
if ( my $init_object = $self->use_init_obj_over_item ? |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
|
|
|
|
|
597
|
|
|
|
|
|
|
($self->init_object || $self->item) : ( $self->item || $self->init_object ) ) { |
598
|
55
|
|
|
|
|
1289
|
$self->_result_from_object( $self->result, $init_object ); |
599
|
|
|
|
|
|
|
} |
600
|
|
|
|
|
|
|
elsif ( !$self->posted ) { |
601
|
|
|
|
|
|
|
# no initial object. empty form must be initialized |
602
|
74
|
|
|
|
|
1707
|
$self->_result_from_fields( $self->result ); |
603
|
|
|
|
|
|
|
} |
604
|
|
|
|
|
|
|
} |
605
|
|
|
|
|
|
|
# if params exist and if posted flag is either not set or set to true |
606
|
283
|
|
|
|
|
6694
|
my $params = clone( $self->params ); |
607
|
283
|
100
|
|
|
|
6859
|
if ( $self->posted ) { |
608
|
165
|
|
|
|
|
4145
|
$self->clear_result; |
609
|
165
|
|
|
|
|
3656
|
$self->_result_from_input( $self->result, $params, 1 ); |
610
|
|
|
|
|
|
|
} |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
} |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
# if active => [...] is set at process time, set 'active' flag |
615
|
|
|
|
|
|
|
sub set_active { |
616
|
279
|
|
|
279
|
0
|
431
|
my $self = shift; |
617
|
279
|
100
|
|
|
|
8323
|
if( $self->has_active ) { |
618
|
1
|
|
|
|
|
2
|
foreach my $fname (@{$self->active}) { |
|
1
|
|
|
|
|
23
|
|
619
|
1
|
|
|
|
|
6
|
my $field = $self->field($fname); |
620
|
1
|
50
|
|
|
|
4
|
if ( $field ) { |
621
|
1
|
|
|
|
|
26
|
$field->_active(1); |
622
|
|
|
|
|
|
|
} |
623
|
|
|
|
|
|
|
else { |
624
|
0
|
|
|
|
|
0
|
warn "field $fname not found to set active"; |
625
|
|
|
|
|
|
|
} |
626
|
|
|
|
|
|
|
} |
627
|
1
|
|
|
|
|
31
|
$self->clear_active; |
628
|
|
|
|
|
|
|
} |
629
|
279
|
100
|
|
|
|
8169
|
if( $self->has_inactive ) { |
630
|
1
|
|
|
|
|
1
|
foreach my $fname (@{$self->inactive}) { |
|
1
|
|
|
|
|
22
|
|
631
|
1
|
|
|
|
|
5
|
my $field = $self->field($fname); |
632
|
1
|
50
|
|
|
|
3
|
if ( $field ) { |
633
|
1
|
|
|
|
|
27
|
$field->_active(0); |
634
|
|
|
|
|
|
|
} |
635
|
|
|
|
|
|
|
else { |
636
|
0
|
|
|
|
|
0
|
warn "field $fname not found to set inactive"; |
637
|
|
|
|
|
|
|
} |
638
|
|
|
|
|
|
|
} |
639
|
1
|
|
|
|
|
37
|
$self->clear_inactive; |
640
|
|
|
|
|
|
|
} |
641
|
|
|
|
|
|
|
} |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
# if active => [...] is set at build time, remove 'inactive' flags |
644
|
|
|
|
|
|
|
sub build_active { |
645
|
1
|
|
|
1
|
0
|
2
|
my $self = shift; |
646
|
1
|
50
|
|
|
|
34
|
if( $self->has_active ) { |
647
|
0
|
|
|
|
|
0
|
foreach my $fname (@{$self->active}) { |
|
0
|
|
|
|
|
0
|
|
648
|
0
|
|
|
|
|
0
|
my $field = $self->field($fname); |
649
|
0
|
0
|
|
|
|
0
|
if( $field ) { |
650
|
0
|
|
|
|
|
0
|
$field->clear_inactive; |
651
|
|
|
|
|
|
|
} |
652
|
|
|
|
|
|
|
else { |
653
|
0
|
|
|
|
|
0
|
warn "field $fname not found to set active"; |
654
|
|
|
|
|
|
|
} |
655
|
|
|
|
|
|
|
} |
656
|
0
|
|
|
|
|
0
|
$self->clear_active; |
657
|
|
|
|
|
|
|
} |
658
|
1
|
50
|
|
|
|
28
|
if( $self->has_inactive ) { |
659
|
1
|
|
|
|
|
5
|
foreach my $fname (@{$self->inactive}) { |
|
1
|
|
|
|
|
28
|
|
660
|
1
|
|
|
|
|
7
|
my $field = $self->field($fname); |
661
|
1
|
50
|
|
|
|
3
|
if( $field ) { |
662
|
1
|
|
|
|
|
26
|
$field->inactive(1); |
663
|
|
|
|
|
|
|
} |
664
|
|
|
|
|
|
|
else { |
665
|
0
|
|
|
|
|
0
|
warn "field $fname not found to set inactive"; |
666
|
|
|
|
|
|
|
} |
667
|
|
|
|
|
|
|
} |
668
|
1
|
|
|
|
|
37
|
$self->clear_inactive; |
669
|
|
|
|
|
|
|
} |
670
|
|
|
|
|
|
|
} |
671
|
|
|
|
|
|
|
|
672
|
76
|
|
|
76
|
1
|
2364
|
sub fif { shift->fields_fif(@_) } |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
# this is subclassed by the model, which may |
675
|
|
|
|
|
|
|
# do a lot more than this |
676
|
|
|
|
|
|
|
sub init_value { |
677
|
257
|
|
|
257
|
0
|
300
|
my ( $self, $field, $value ) = @_; |
678
|
257
|
|
|
|
|
6292
|
$field->init_value($value); |
679
|
257
|
|
|
|
|
944
|
$field->_set_value($value); |
680
|
|
|
|
|
|
|
} |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
sub _set_dependency { |
683
|
165
|
|
|
165
|
|
276
|
my $self = shift; |
684
|
|
|
|
|
|
|
|
685
|
165
|
|
100
|
|
|
4277
|
my $depends = $self->dependency || return; |
686
|
9
|
|
|
|
|
235
|
my $params = $self->params; |
687
|
9
|
|
|
|
|
24
|
for my $group (@$depends) { |
688
|
10
|
50
|
|
|
|
32
|
next if @$group < 2; |
689
|
|
|
|
|
|
|
# process a group of fields |
690
|
10
|
|
|
|
|
22
|
for my $name (@$group) { |
691
|
|
|
|
|
|
|
# is there a value? |
692
|
27
|
|
|
|
|
41
|
my $value = $params->{$name}; |
693
|
27
|
100
|
|
|
|
57
|
next unless defined $value; |
694
|
|
|
|
|
|
|
# The exception is a boolean can be zero which we count as not set. |
695
|
|
|
|
|
|
|
# This is to allow requiring a field when a boolean is true. |
696
|
2
|
|
|
|
|
16
|
my $field = $self->field($name); |
697
|
2
|
50
|
33
|
|
|
6
|
next if $self->field($name)->type eq 'Boolean' && $value == 0; |
698
|
2
|
50
|
|
|
|
9
|
next unless HTML::FormHandler::Field::has_some_value($value); |
699
|
|
|
|
|
|
|
# one field was found non-blank, so set all to required |
700
|
2
|
|
|
|
|
5
|
for (@$group) { |
701
|
6
|
|
|
|
|
12
|
my $field = $self->field($_); |
702
|
6
|
50
|
33
|
|
|
148
|
next unless $field && !$field->required; |
703
|
6
|
|
|
|
|
169
|
$self->add_required($field); # save for clearing later. |
704
|
6
|
|
|
|
|
137
|
$field->required(1); |
705
|
|
|
|
|
|
|
} |
706
|
2
|
|
|
|
|
4
|
last; |
707
|
|
|
|
|
|
|
} |
708
|
|
|
|
|
|
|
} |
709
|
|
|
|
|
|
|
} |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
sub _clear_dependency { |
712
|
165
|
|
|
165
|
|
277
|
my $self = shift; |
713
|
|
|
|
|
|
|
|
714
|
165
|
|
|
|
|
236
|
$_->required(0) for @{$self->_required}; |
|
165
|
|
|
|
|
4487
|
|
715
|
165
|
|
|
|
|
5369
|
$self->clear_required; |
716
|
|
|
|
|
|
|
} |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
sub peek { |
719
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
720
|
0
|
|
|
|
|
0
|
my $string = "Form " . $self->name . "\n"; |
721
|
0
|
|
|
|
|
0
|
my $indent = ' '; |
722
|
0
|
|
|
|
|
0
|
foreach my $field ( $self->sorted_fields ) { |
723
|
0
|
|
|
|
|
0
|
$string .= $field->peek( $indent ); |
724
|
|
|
|
|
|
|
} |
725
|
0
|
|
|
|
|
0
|
return $string; |
726
|
|
|
|
|
|
|
} |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
sub _munge_params { |
729
|
354
|
|
|
354
|
|
533
|
my ( $self, $params, $attr ) = @_; |
730
|
354
|
50
|
|
|
|
8845
|
my $_fix_params = $self->params_class->new( @{ $self->params_args || [] } ); |
|
354
|
|
|
|
|
8298
|
|
731
|
354
|
|
|
|
|
1421
|
my $new_params = $_fix_params->expand_hash($params); |
732
|
354
|
100
|
|
|
|
9143
|
if ( $self->html_prefix ) { |
733
|
6
|
|
|
|
|
150
|
$new_params = $new_params->{ $self->name }; |
734
|
|
|
|
|
|
|
} |
735
|
354
|
100
|
|
|
|
801
|
$new_params = {} if !defined $new_params; |
736
|
354
|
|
|
|
|
9208
|
$self->{params} = $new_params; |
737
|
|
|
|
|
|
|
} |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
sub params_to_values { |
740
|
1
|
|
|
1
|
0
|
2
|
my ( $self, $params ) = @_; |
741
|
1
|
50
|
|
|
|
30
|
my $_fix_params = $self->params_class->new( @{ $self->params_args || [] } ); |
|
1
|
|
|
|
|
23
|
|
742
|
1
|
|
|
|
|
5
|
my $new_params = $_fix_params->expand_hash($params); |
743
|
1
|
|
|
|
|
29
|
return $new_params; |
744
|
|
|
|
|
|
|
} |
745
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
sub add_form_error { |
747
|
4
|
|
|
4
|
0
|
97
|
my ( $self, @message ) = @_; |
748
|
|
|
|
|
|
|
|
749
|
4
|
50
|
|
|
|
12
|
unless ( defined $message[0] ) { |
750
|
0
|
|
|
|
|
0
|
@message = ('form is invalid'); |
751
|
|
|
|
|
|
|
} |
752
|
4
|
|
|
|
|
4
|
my $out; |
753
|
|
|
|
|
|
|
try { |
754
|
4
|
|
|
4
|
|
127
|
$out = $self->_localize(@message); |
755
|
|
|
|
|
|
|
} |
756
|
|
|
|
|
|
|
catch { |
757
|
0
|
|
|
0
|
|
0
|
die "Error occurred localizing error message for " . $self->name . ". $_"; |
758
|
4
|
|
|
|
|
37
|
}; |
759
|
4
|
|
|
|
|
63
|
$self->push_form_errors($out); |
760
|
4
|
|
|
|
|
9
|
return; |
761
|
|
|
|
|
|
|
} |
762
|
|
|
|
|
|
|
|
763
|
|
|
|
308
|
0
|
|
sub get_default_value { } |
764
|
|
|
|
0
|
|
|
sub _can_deflate { } |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
sub update_fields { |
767
|
281
|
|
|
281
|
0
|
406
|
my $self = shift; |
768
|
281
|
100
|
|
|
|
9360
|
if( $self->has_update_field_list ) { |
769
|
4
|
|
|
|
|
92
|
my $updates = $self->update_field_list; |
770
|
4
|
|
|
|
|
3
|
foreach my $field_name ( keys %{$updates} ) { |
|
4
|
|
|
|
|
14
|
|
771
|
6
|
|
|
|
|
21
|
$self->update_field($field_name, $updates->{$field_name} ); |
772
|
|
|
|
|
|
|
} |
773
|
4
|
|
|
|
|
136
|
$self->clear_update_field_list; |
774
|
|
|
|
|
|
|
} |
775
|
281
|
100
|
|
|
|
8933
|
if( $self->has_defaults ) { |
776
|
2
|
|
|
|
|
43
|
my $defaults = $self->defaults; |
777
|
2
|
|
|
|
|
3
|
foreach my $field_name ( keys %{$defaults} ) { |
|
2
|
|
|
|
|
5
|
|
778
|
5
|
|
|
|
|
17
|
$self->update_field($field_name, { default => $defaults->{$field_name} } ); |
779
|
|
|
|
|
|
|
} |
780
|
2
|
|
|
|
|
60
|
$self->clear_defaults; |
781
|
|
|
|
|
|
|
} |
782
|
|
|
|
|
|
|
} |
783
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
sub update_field { |
785
|
11
|
|
|
11
|
0
|
15
|
my ( $self, $field_name, $updates ) = @_; |
786
|
|
|
|
|
|
|
|
787
|
11
|
|
|
|
|
30
|
my $field = $self->field($field_name); |
788
|
11
|
50
|
|
|
|
30
|
unless( $field ) { |
789
|
0
|
|
|
|
|
0
|
die "Field $field_name is not found and cannot be updated by update_fields"; |
790
|
|
|
|
|
|
|
} |
791
|
11
|
|
|
|
|
12
|
while ( my ( $attr_name, $attr_value ) = each %{$updates} ) { |
|
24
|
|
|
|
|
69
|
|
792
|
13
|
50
|
|
|
|
54
|
confess "invalid attribute '$attr_name' passed to update_field" |
793
|
|
|
|
|
|
|
unless $field->can($attr_name); |
794
|
13
|
100
|
|
|
|
27
|
if( $attr_name eq 'tags' ) { |
795
|
1
|
|
|
|
|
43
|
$field->set_tag(%$attr_value); |
796
|
|
|
|
|
|
|
} |
797
|
|
|
|
|
|
|
else { |
798
|
12
|
|
|
|
|
294
|
$field->$attr_name($attr_value); |
799
|
|
|
|
|
|
|
} |
800
|
|
|
|
|
|
|
} |
801
|
|
|
|
|
|
|
} |
802
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
805
|
141
|
|
|
141
|
|
942
|
use namespace::autoclean; |
|
141
|
|
|
|
|
240
|
|
|
141
|
|
|
|
|
748
|
|
806
|
|
|
|
|
|
|
1; |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
__END__ |
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
=pod |
811
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
=encoding UTF-8 |
813
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
=head1 NAME |
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
HTML::FormHandler - HTML forms using Moose |
817
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
=head1 VERSION |
819
|
|
|
|
|
|
|
|
820
|
|
|
|
|
|
|
version 0.40067 |
821
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
=head1 SYNOPSIS |
823
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
See the manual at L<HTML::FormHandler::Manual>. |
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
use HTML::FormHandler; # or a custom form: use MyApp::Form::User; |
827
|
|
|
|
|
|
|
my $form = HTML::FormHandler->new( .... ); |
828
|
|
|
|
|
|
|
$form->process( params => $params ); |
829
|
|
|
|
|
|
|
my $rendered_form = $form->render; |
830
|
|
|
|
|
|
|
if( $form->validated ) { |
831
|
|
|
|
|
|
|
# perform validated form actions |
832
|
|
|
|
|
|
|
} |
833
|
|
|
|
|
|
|
else { |
834
|
|
|
|
|
|
|
# perform non-validated actions |
835
|
|
|
|
|
|
|
} |
836
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
Or, if you want to use a form 'result' (which contains only the form |
838
|
|
|
|
|
|
|
values and error messages) instead: |
839
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
use MyApp::Form; # or a generic form: use HTML::FormHandler; |
841
|
|
|
|
|
|
|
my $form = MyApp::Form->new( .... ); |
842
|
|
|
|
|
|
|
my $result = $form->run( params => $params ); |
843
|
|
|
|
|
|
|
if( $result->validated ) { |
844
|
|
|
|
|
|
|
# perform validated form actions |
845
|
|
|
|
|
|
|
} |
846
|
|
|
|
|
|
|
else { |
847
|
|
|
|
|
|
|
# perform non-validated actions |
848
|
|
|
|
|
|
|
$result->render; |
849
|
|
|
|
|
|
|
} |
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
An example of a custom form class: |
852
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
package MyApp::Form::User; |
854
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
use HTML::FormHandler::Moose; |
856
|
|
|
|
|
|
|
extends 'HTML::FormHandler'; |
857
|
|
|
|
|
|
|
use Moose::Util::TypeConstraints; |
858
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
has '+item_class' => ( default => 'User' ); |
860
|
|
|
|
|
|
|
|
861
|
|
|
|
|
|
|
has_field 'name' => ( type => 'Text' ); |
862
|
|
|
|
|
|
|
has_field 'age' => ( type => 'PosInteger', apply => [ 'MinimumAge' ] ); |
863
|
|
|
|
|
|
|
has_field 'birthdate' => ( type => 'DateTime' ); |
864
|
|
|
|
|
|
|
has_field 'birthdate.month' => ( type => 'Month' ); |
865
|
|
|
|
|
|
|
has_field 'birthdate.day' => ( type => 'MonthDay' ); |
866
|
|
|
|
|
|
|
has_field 'birthdate.year' => ( type => 'Year' ); |
867
|
|
|
|
|
|
|
has_field 'hobbies' => ( type => 'Multiple' ); |
868
|
|
|
|
|
|
|
has_field 'address' => ( type => 'Text' ); |
869
|
|
|
|
|
|
|
has_field 'city' => ( type => 'Text' ); |
870
|
|
|
|
|
|
|
has_field 'state' => ( type => 'Select' ); |
871
|
|
|
|
|
|
|
has_field 'email' => ( type => 'Email' ); |
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
has '+dependency' => ( default => sub { |
874
|
|
|
|
|
|
|
[ ['address', 'city', 'state'], ] |
875
|
|
|
|
|
|
|
} |
876
|
|
|
|
|
|
|
); |
877
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
subtype 'MinimumAge' |
879
|
|
|
|
|
|
|
=> as 'Int' |
880
|
|
|
|
|
|
|
=> where { $_ > 13 } |
881
|
|
|
|
|
|
|
=> message { "You are not old enough to register" }; |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
no HTML::FormHandler::Moose; |
884
|
|
|
|
|
|
|
1; |
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
A dynamic form - one that does not use a custom form class - may be |
887
|
|
|
|
|
|
|
created using the 'field_list' attribute to set fields: |
888
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
my $form = HTML::FormHandler->new( |
890
|
|
|
|
|
|
|
name => 'user_form', |
891
|
|
|
|
|
|
|
item => $user, |
892
|
|
|
|
|
|
|
field_list => [ |
893
|
|
|
|
|
|
|
'username' => { |
894
|
|
|
|
|
|
|
type => 'Text', |
895
|
|
|
|
|
|
|
apply => [ { check => qr/^[0-9a-z]*\z/, |
896
|
|
|
|
|
|
|
message => 'Contains invalid characters' } ], |
897
|
|
|
|
|
|
|
}, |
898
|
|
|
|
|
|
|
'select_bar' => { |
899
|
|
|
|
|
|
|
type => 'Select', |
900
|
|
|
|
|
|
|
options => \@select_options, |
901
|
|
|
|
|
|
|
multiple => 1, |
902
|
|
|
|
|
|
|
size => 4, |
903
|
|
|
|
|
|
|
}, |
904
|
|
|
|
|
|
|
], |
905
|
|
|
|
|
|
|
); |
906
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
FormHandler does not provide a custom controller for Catalyst because |
908
|
|
|
|
|
|
|
it isn't necessary. Interfacing to FormHandler is only a couple of |
909
|
|
|
|
|
|
|
lines of code. See L<HTML::FormHandler::Manual::Catalyst> for more |
910
|
|
|
|
|
|
|
details, or L<Catalyst::Manual::Tutorial::09_AdvancedCRUD::09_FormHandler>. |
911
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
=head1 DESCRIPTION |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
*** Although documentation in this file provides some overview, it is mainly |
915
|
|
|
|
|
|
|
intended for API documentation. See L<HTML::FormHandler::Manual::Intro> |
916
|
|
|
|
|
|
|
for an introduction, with links to other documentation. |
917
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
HTML::FormHandler maintains a clean separation between form construction |
919
|
|
|
|
|
|
|
and form rendering. It allows you to define your forms and fields in a |
920
|
|
|
|
|
|
|
number of flexible ways. Although it provides renderers for HTML, you |
921
|
|
|
|
|
|
|
can define custom renderers for any kind of presentation. |
922
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
HTML::FormHandler allows you to define form fields and validators. It can |
924
|
|
|
|
|
|
|
be used for both database and non-database forms, and will |
925
|
|
|
|
|
|
|
automatically update or create rows in a database. It can be used |
926
|
|
|
|
|
|
|
to process structured data that doesn't come from an HTML form. |
927
|
|
|
|
|
|
|
|
928
|
|
|
|
|
|
|
One of its goals is to keep the controller/application program interface as |
929
|
|
|
|
|
|
|
simple as possible, and to minimize the duplication of code. In most cases, |
930
|
|
|
|
|
|
|
interfacing your controller to your form is only a few lines of code. |
931
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
With FormHandler you shouldn't have to spend hours trying to figure out how to make a |
933
|
|
|
|
|
|
|
simple HTML change that would take one minute by hand. Because you _can_ do it |
934
|
|
|
|
|
|
|
by hand. Or you can automate HTML generation as much as you want, with |
935
|
|
|
|
|
|
|
template widgets or pure Perl rendering classes, and stay completely in |
936
|
|
|
|
|
|
|
control of what, where, and how much is done automatically. You can define |
937
|
|
|
|
|
|
|
custom renderers and display your rendered forms however you want. |
938
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
You can split the pieces of your forms up into logical parts and compose |
940
|
|
|
|
|
|
|
complete forms from FormHandler classes, roles, fields, collections of |
941
|
|
|
|
|
|
|
validations, transformations and Moose type constraints. |
942
|
|
|
|
|
|
|
You can write custom methods to process forms, add any attribute you like, |
943
|
|
|
|
|
|
|
and use Moose method modifiers. FormHandler forms are Perl classes, so there's |
944
|
|
|
|
|
|
|
a lot of flexibility in what you can do. |
945
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
HTML::FormHandler provides rendering through roles which are applied to |
947
|
|
|
|
|
|
|
form and field classes (although there's no reason you couldn't write |
948
|
|
|
|
|
|
|
a renderer as an external object either). There are currently two flavors: |
949
|
|
|
|
|
|
|
all-in-one solutions like L<HTML::FormHandler::Render::Simple> and |
950
|
|
|
|
|
|
|
L<HTML::FormHandler::Render::Table> that contain methods for rendering |
951
|
|
|
|
|
|
|
field widget classes, and the L<HTML::FormHandler::Widget> roles, which are |
952
|
|
|
|
|
|
|
more atomic roles which are automatically applied to fields and form. See |
953
|
|
|
|
|
|
|
L<HTML::FormHandler::Manual::Rendering> for more details. |
954
|
|
|
|
|
|
|
(And you can easily use hand-built forms - FormHandler doesn't care.) |
955
|
|
|
|
|
|
|
|
956
|
|
|
|
|
|
|
The typical application for FormHandler would be in a Catalyst, DBIx::Class, |
957
|
|
|
|
|
|
|
Template Toolkit web application, but use is not limited to that. FormHandler |
958
|
|
|
|
|
|
|
can be used in any Perl application. |
959
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
More Formhandler documentation and a tutorial can be found in the manual |
961
|
|
|
|
|
|
|
at L<HTML::FormHandler::Manual>. |
962
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
=head1 ATTRIBUTES and METHODS |
964
|
|
|
|
|
|
|
|
965
|
|
|
|
|
|
|
=head2 Creating a form with 'new' |
966
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
The new constructor takes name/value pairs: |
968
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
MyForm->new( |
970
|
|
|
|
|
|
|
item => $item, |
971
|
|
|
|
|
|
|
); |
972
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
No attributes are required on new. The form's fields will be built from |
974
|
|
|
|
|
|
|
the form definitions. If no initial data object or defaults have been provided, the form |
975
|
|
|
|
|
|
|
will be empty. Most attributes can be set on either 'new' or 'process'. |
976
|
|
|
|
|
|
|
The common attributes to be passed in to the constructor for a database form |
977
|
|
|
|
|
|
|
are either item_id and schema or item: |
978
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
item_id - database row primary key |
980
|
|
|
|
|
|
|
item - database row object |
981
|
|
|
|
|
|
|
schema - (for DBIC) the DBIx::Class schema |
982
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
The following are sometimes passed in, but are also often set |
984
|
|
|
|
|
|
|
in the form class: |
985
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
item_class - source name of row |
987
|
|
|
|
|
|
|
dependency - (see dependency) |
988
|
|
|
|
|
|
|
field_list - an array of field definitions |
989
|
|
|
|
|
|
|
init_object - a hashref or object to provide initial values |
990
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
Examples of creating a form object with new: |
992
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
my $form = MyApp::Form::User->new; |
994
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
# database form using a row object |
996
|
|
|
|
|
|
|
my $form = MyApp::Form::Member->new( item => $row ); |
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
# a dynamic form (no form class has been defined) |
999
|
|
|
|
|
|
|
my $form = HTML::FormHandler::Model::DBIC->new( |
1000
|
|
|
|
|
|
|
item_id => $id, |
1001
|
|
|
|
|
|
|
item_class => 'User', |
1002
|
|
|
|
|
|
|
schema => $schema, |
1003
|
|
|
|
|
|
|
field_list => [ |
1004
|
|
|
|
|
|
|
name => 'Text', |
1005
|
|
|
|
|
|
|
active => 'Boolean', |
1006
|
|
|
|
|
|
|
submit_btn => 'Submit', |
1007
|
|
|
|
|
|
|
], |
1008
|
|
|
|
|
|
|
); |
1009
|
|
|
|
|
|
|
|
1010
|
|
|
|
|
|
|
See the model class for more information about 'item', 'item_id', |
1011
|
|
|
|
|
|
|
'item_class', and 'schema' (for the DBIC model). |
1012
|
|
|
|
|
|
|
L<HTML::FormHandler::Model::DBIC>. |
1013
|
|
|
|
|
|
|
|
1014
|
|
|
|
|
|
|
FormHandler forms are handled in two steps: 1) create with 'new', |
1015
|
|
|
|
|
|
|
2) handle with 'process'. FormHandler doesn't |
1016
|
|
|
|
|
|
|
care whether most parameters are set on new or process or update, |
1017
|
|
|
|
|
|
|
but a 'field_list' argument must be passed in on 'new' since the |
1018
|
|
|
|
|
|
|
fields are built at construction time. |
1019
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
If you want to update field attributes on the 'process' call, you can |
1021
|
|
|
|
|
|
|
use an 'update_field_list' or 'defaults' hashref attribute , or subclass |
1022
|
|
|
|
|
|
|
update_fields in your form. The 'update_field_list' hashref can be used |
1023
|
|
|
|
|
|
|
to set any field attribute. The 'defaults' hashref will update only |
1024
|
|
|
|
|
|
|
the 'default' attribute in the field. (There are a lot of ways to |
1025
|
|
|
|
|
|
|
set defaults. See L<HTML::FormHandler::Manual::Defaults>.) |
1026
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
$form->process( defaults => { foo => 'foo_def', bar => 'bar_def' } ); |
1028
|
|
|
|
|
|
|
$form->process( update_field_list => { foo => { label => 'New Label' } }); |
1029
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
Field results are built on the 'new' call, but will then be re-built |
1031
|
|
|
|
|
|
|
on the process call. If you always use 'process' before rendering the form, |
1032
|
|
|
|
|
|
|
accessing fields, etc, you can set the 'no_preload' flag to skip this step. |
1033
|
|
|
|
|
|
|
|
1034
|
|
|
|
|
|
|
=head2 Processing the form |
1035
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
=head3 process |
1037
|
|
|
|
|
|
|
|
1038
|
|
|
|
|
|
|
Call the 'process' method on your form to perform validation and |
1039
|
|
|
|
|
|
|
update. A database form must have either an item (row object) or |
1040
|
|
|
|
|
|
|
a schema, item_id (row primary key), and item_class (usually set in the form). |
1041
|
|
|
|
|
|
|
A non-database form requires only parameters. |
1042
|
|
|
|
|
|
|
|
1043
|
|
|
|
|
|
|
$form->process( item => $book, params => $c->req->parameters ); |
1044
|
|
|
|
|
|
|
$form->process( item_id => $item_id, |
1045
|
|
|
|
|
|
|
schema => $schema, params => $c->req->parameters ); |
1046
|
|
|
|
|
|
|
$form->process( params => $c->req->parameters ); |
1047
|
|
|
|
|
|
|
|
1048
|
|
|
|
|
|
|
This process method returns the 'validated' flag (C<< $form->validated >>). |
1049
|
|
|
|
|
|
|
If it is a database form and the form validates, the database row |
1050
|
|
|
|
|
|
|
will be updated. |
1051
|
|
|
|
|
|
|
|
1052
|
|
|
|
|
|
|
After the form has been processed, you can get a parameter hashref suitable |
1053
|
|
|
|
|
|
|
for using to fill in the form from C<< $form->fif >>. |
1054
|
|
|
|
|
|
|
A hash of inflated values (that would be used to update the database for |
1055
|
|
|
|
|
|
|
a database form) can be retrieved with C<< $form->value >>. |
1056
|
|
|
|
|
|
|
|
1057
|
|
|
|
|
|
|
If you don't want to update the database on this process call, you can |
1058
|
|
|
|
|
|
|
set the 'no_update' flag: |
1059
|
|
|
|
|
|
|
|
1060
|
|
|
|
|
|
|
$form->process( item => $book, params => $params, no_update => 1 ); |
1061
|
|
|
|
|
|
|
|
1062
|
|
|
|
|
|
|
=head3 params |
1063
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
Parameters are passed in when you call 'process'. |
1065
|
|
|
|
|
|
|
HFH gets data to validate and store in the database from the params hash. |
1066
|
|
|
|
|
|
|
If the params hash is empty, no validation is done, so it is not necessary |
1067
|
|
|
|
|
|
|
to check for POST before calling C<< $form->process >>. (Although see |
1068
|
|
|
|
|
|
|
the 'posted' option for complications.) |
1069
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
Params can either be in the form of CGI/HTTP style params: |
1071
|
|
|
|
|
|
|
|
1072
|
|
|
|
|
|
|
{ |
1073
|
|
|
|
|
|
|
user_name => "Joe Smith", |
1074
|
|
|
|
|
|
|
occupation => "Programmer", |
1075
|
|
|
|
|
|
|
'addresses.0.street' => "999 Main Street", |
1076
|
|
|
|
|
|
|
'addresses.0.city' => "Podunk", |
1077
|
|
|
|
|
|
|
'addresses.0.country' => "UT", |
1078
|
|
|
|
|
|
|
'addresses.0.address_id' => "1", |
1079
|
|
|
|
|
|
|
'addresses.1.street' => "333 Valencia Street", |
1080
|
|
|
|
|
|
|
'addresses.1.city' => "San Francisco", |
1081
|
|
|
|
|
|
|
'addresses.1.country' => "UT", |
1082
|
|
|
|
|
|
|
'addresses.1.address_id' => "2", |
1083
|
|
|
|
|
|
|
} |
1084
|
|
|
|
|
|
|
|
1085
|
|
|
|
|
|
|
or as structured data in the form of hashes and lists: |
1086
|
|
|
|
|
|
|
|
1087
|
|
|
|
|
|
|
{ |
1088
|
|
|
|
|
|
|
addresses => [ |
1089
|
|
|
|
|
|
|
{ |
1090
|
|
|
|
|
|
|
city => 'Middle City', |
1091
|
|
|
|
|
|
|
country => 'GK', |
1092
|
|
|
|
|
|
|
address_id => 1, |
1093
|
|
|
|
|
|
|
street => '101 Main St', |
1094
|
|
|
|
|
|
|
}, |
1095
|
|
|
|
|
|
|
{ |
1096
|
|
|
|
|
|
|
city => 'DownTown', |
1097
|
|
|
|
|
|
|
country => 'UT', |
1098
|
|
|
|
|
|
|
address_id => 2, |
1099
|
|
|
|
|
|
|
street => '99 Elm St', |
1100
|
|
|
|
|
|
|
}, |
1101
|
|
|
|
|
|
|
], |
1102
|
|
|
|
|
|
|
'occupation' => 'management', |
1103
|
|
|
|
|
|
|
'user_name' => 'jdoe', |
1104
|
|
|
|
|
|
|
} |
1105
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
CGI style parameters will be converted to hashes and lists for HFH to |
1107
|
|
|
|
|
|
|
operate on. |
1108
|
|
|
|
|
|
|
|
1109
|
|
|
|
|
|
|
=head3 posted |
1110
|
|
|
|
|
|
|
|
1111
|
|
|
|
|
|
|
Note that FormHandler by default uses empty params as a signal that the |
1112
|
|
|
|
|
|
|
form has not actually been posted, and so will not attempt to validate |
1113
|
|
|
|
|
|
|
a form with empty params. Most of the time this works OK, but if you |
1114
|
|
|
|
|
|
|
have a small form with only the controls that do not return a post |
1115
|
|
|
|
|
|
|
parameter if unselected (checkboxes and select lists), then the form |
1116
|
|
|
|
|
|
|
will not be validated if everything is unselected. For this case you |
1117
|
|
|
|
|
|
|
can either add a hidden field as an 'indicator', or use the 'posted' flag: |
1118
|
|
|
|
|
|
|
|
1119
|
|
|
|
|
|
|
$form->process( posted => ($c->req->method eq 'POST'), params => ... ); |
1120
|
|
|
|
|
|
|
|
1121
|
|
|
|
|
|
|
The 'posted' flag also works to prevent validation from being performed |
1122
|
|
|
|
|
|
|
if there are extra params in the params hash and it is not a 'POST' request. |
1123
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
=head2 Getting data out |
1125
|
|
|
|
|
|
|
|
1126
|
|
|
|
|
|
|
=head3 fif (fill in form) |
1127
|
|
|
|
|
|
|
|
1128
|
|
|
|
|
|
|
If you don't use FormHandler rendering and want to fill your form values in |
1129
|
|
|
|
|
|
|
using some other method (such as with HTML::FillInForm or using a template) |
1130
|
|
|
|
|
|
|
this returns a hash of values that are equivalent to params which you may |
1131
|
|
|
|
|
|
|
use to fill in your form. |
1132
|
|
|
|
|
|
|
|
1133
|
|
|
|
|
|
|
The fif value for a 'title' field in a TT form: |
1134
|
|
|
|
|
|
|
|
1135
|
|
|
|
|
|
|
[% form.fif.title %] |
1136
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
Or you can use the 'fif' method on individual fields: |
1138
|
|
|
|
|
|
|
|
1139
|
|
|
|
|
|
|
[% form.field('title').fif %] |
1140
|
|
|
|
|
|
|
|
1141
|
|
|
|
|
|
|
If you use FormHandler to render your forms or field you probably won't use |
1142
|
|
|
|
|
|
|
these methods. |
1143
|
|
|
|
|
|
|
|
1144
|
|
|
|
|
|
|
=head3 value |
1145
|
|
|
|
|
|
|
|
1146
|
|
|
|
|
|
|
Returns a hashref of all field values. Useful for non-database forms, or if |
1147
|
|
|
|
|
|
|
you want to update the database yourself. The 'fif' method returns |
1148
|
|
|
|
|
|
|
a hashref with the field names for the keys and the field's 'fif' for the |
1149
|
|
|
|
|
|
|
values; 'value' returns a hashref with the field accessors for the keys, and the |
1150
|
|
|
|
|
|
|
field's 'value' (possibly inflated) for the values. |
1151
|
|
|
|
|
|
|
|
1152
|
|
|
|
|
|
|
Forms containing arrays to be processed with L<HTML::FormHandler::Field::Repeatable> |
1153
|
|
|
|
|
|
|
will have parameters with dots and numbers, like 'addresses.0.city', while the |
1154
|
|
|
|
|
|
|
values hash will transform the fields with numbers to arrays. |
1155
|
|
|
|
|
|
|
|
1156
|
|
|
|
|
|
|
=head2 Accessing and setting up fields |
1157
|
|
|
|
|
|
|
|
1158
|
|
|
|
|
|
|
Fields are declared with a number of attributes which are defined in |
1159
|
|
|
|
|
|
|
L<HTML::FormHandler::Field>. If you want additional attributes you can |
1160
|
|
|
|
|
|
|
define your own field classes (or apply a role to a field class - see |
1161
|
|
|
|
|
|
|
L<HTML::FormHandler::Manual::Cookbook>). The field 'type' (used in field |
1162
|
|
|
|
|
|
|
definitions) is the short class name of the field class, used when |
1163
|
|
|
|
|
|
|
searching the 'field_name_space' for the field class. |
1164
|
|
|
|
|
|
|
|
1165
|
|
|
|
|
|
|
=head3 has_field |
1166
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
The most common way of declaring fields is the 'has_field' syntax. |
1168
|
|
|
|
|
|
|
Using the 'has_field' syntax sugar requires C< use HTML::FormHandler::Moose; > |
1169
|
|
|
|
|
|
|
or C< use HTML::FormHandler::Moose::Role; > in a role. |
1170
|
|
|
|
|
|
|
See L<HTML::FormHandler::Manual::Intro> |
1171
|
|
|
|
|
|
|
|
1172
|
|
|
|
|
|
|
use HTML::FormHandler::Moose; |
1173
|
|
|
|
|
|
|
has_field 'field_name' => ( type => 'FieldClass', .... ); |
1174
|
|
|
|
|
|
|
|
1175
|
|
|
|
|
|
|
=head3 field_list |
1176
|
|
|
|
|
|
|
|
1177
|
|
|
|
|
|
|
A 'field_list' is an array of field definitions which can be used as an |
1178
|
|
|
|
|
|
|
alternative to 'has_field' in small, dynamic forms to create fields. |
1179
|
|
|
|
|
|
|
|
1180
|
|
|
|
|
|
|
field_list => [ |
1181
|
|
|
|
|
|
|
field_one => { |
1182
|
|
|
|
|
|
|
type => 'Text', |
1183
|
|
|
|
|
|
|
required => 1 |
1184
|
|
|
|
|
|
|
}, |
1185
|
|
|
|
|
|
|
field_two => 'Text, |
1186
|
|
|
|
|
|
|
] |
1187
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
The field_list array takes elements which are either a field_name key |
1189
|
|
|
|
|
|
|
pointing to a 'type' string or a field_name key pointing to a |
1190
|
|
|
|
|
|
|
hashref of field attributes. You can also provide an array of |
1191
|
|
|
|
|
|
|
hashref elements with the name as an additional attribute. |
1192
|
|
|
|
|
|
|
The field list can be set inside a form class, when you want to |
1193
|
|
|
|
|
|
|
add fields to the form depending on some other state, although |
1194
|
|
|
|
|
|
|
you can also create all the fields and set some of them inactive. |
1195
|
|
|
|
|
|
|
|
1196
|
|
|
|
|
|
|
sub field_list { |
1197
|
|
|
|
|
|
|
my $self = shift; |
1198
|
|
|
|
|
|
|
my $fields = $self->schema->resultset('SomeTable')-> |
1199
|
|
|
|
|
|
|
search({user_id => $self->user_id, .... }); |
1200
|
|
|
|
|
|
|
my @field_list; |
1201
|
|
|
|
|
|
|
while ( my $field = $fields->next ) |
1202
|
|
|
|
|
|
|
{ |
1203
|
|
|
|
|
|
|
< create field list > |
1204
|
|
|
|
|
|
|
} |
1205
|
|
|
|
|
|
|
return \@field_list; |
1206
|
|
|
|
|
|
|
} |
1207
|
|
|
|
|
|
|
|
1208
|
|
|
|
|
|
|
=head3 update_field_list |
1209
|
|
|
|
|
|
|
|
1210
|
|
|
|
|
|
|
Used to dynamically set particular field attributes on the 'process' (or |
1211
|
|
|
|
|
|
|
'run') call. (Will not create fields.) |
1212
|
|
|
|
|
|
|
|
1213
|
|
|
|
|
|
|
$form->process( update_field_list => { |
1214
|
|
|
|
|
|
|
foo_date => { format => '%m/%e/%Y', date_start => '10-01-01' } }, |
1215
|
|
|
|
|
|
|
params => $params ); |
1216
|
|
|
|
|
|
|
|
1217
|
|
|
|
|
|
|
The 'update_field_list' is processed by the 'update_fields' form method, |
1218
|
|
|
|
|
|
|
which can also be used in a form to do specific field updates: |
1219
|
|
|
|
|
|
|
|
1220
|
|
|
|
|
|
|
sub update_fields { |
1221
|
|
|
|
|
|
|
my $self = shift; |
1222
|
|
|
|
|
|
|
$self->field('foo')->temp( 'foo_temp' ); |
1223
|
|
|
|
|
|
|
$self->field('bar')->default( 'foo_value' ); |
1224
|
|
|
|
|
|
|
$self->next::method(); |
1225
|
|
|
|
|
|
|
} |
1226
|
|
|
|
|
|
|
|
1227
|
|
|
|
|
|
|
(Note that you although you can set a field's 'default', you can't set a |
1228
|
|
|
|
|
|
|
field's 'value' directly here, since it will |
1229
|
|
|
|
|
|
|
be overwritten by the validation process. Set the value in a field |
1230
|
|
|
|
|
|
|
validation method.) |
1231
|
|
|
|
|
|
|
|
1232
|
|
|
|
|
|
|
=head3 update_subfields |
1233
|
|
|
|
|
|
|
|
1234
|
|
|
|
|
|
|
Yet another way to provide settings for the field, except this one is intended for |
1235
|
|
|
|
|
|
|
use in roles and compound fields, and is only executed when the form is |
1236
|
|
|
|
|
|
|
initially built. It takes the same field name keys as 'update_field_list', plus |
1237
|
|
|
|
|
|
|
'all', 'by_flag', and 'by_type'. |
1238
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
sub build_update_subfields {{ |
1240
|
|
|
|
|
|
|
all => { tags => { wrapper_tag => 'p' } }, |
1241
|
|
|
|
|
|
|
foo => { element_class => 'blue' }, |
1242
|
|
|
|
|
|
|
}} |
1243
|
|
|
|
|
|
|
|
1244
|
|
|
|
|
|
|
The 'all' hash key will apply updates to all fields. (Conflicting attributes |
1245
|
|
|
|
|
|
|
in a field definition take precedence.) |
1246
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
The 'by_flag' hash key will apply updates to fields with a particular flag. |
1248
|
|
|
|
|
|
|
The currently supported subkeys are 'compound', 'contains', and 'repeatable'. |
1249
|
|
|
|
|
|
|
(For repeatable instances, in addition to 'contains' you can also use the |
1250
|
|
|
|
|
|
|
'repeatable' key and the 'init_contains' attribute.) |
1251
|
|
|
|
|
|
|
This is useful for turning on the rendering |
1252
|
|
|
|
|
|
|
wrappers for compounds and repeatables, which are off by default. (The |
1253
|
|
|
|
|
|
|
repeatable instances are wrapped by default.) |
1254
|
|
|
|
|
|
|
|
1255
|
|
|
|
|
|
|
sub build_update_subfields {{ |
1256
|
|
|
|
|
|
|
by_flag => { compound => { do_wrapper => 1 } }, |
1257
|
|
|
|
|
|
|
by_type => { Select => { element_class => ['sel_elem'] } }, |
1258
|
|
|
|
|
|
|
}} |
1259
|
|
|
|
|
|
|
|
1260
|
|
|
|
|
|
|
The 'by_type' hash key will provide values to all fields of a particular |
1261
|
|
|
|
|
|
|
type. |
1262
|
|
|
|
|
|
|
|
1263
|
|
|
|
|
|
|
=head3 defaults |
1264
|
|
|
|
|
|
|
|
1265
|
|
|
|
|
|
|
This is a more specialized version of the 'update_field_list'. It can be |
1266
|
|
|
|
|
|
|
used to provide 'default' settings for fields, in a shorthand way (you don't |
1267
|
|
|
|
|
|
|
have to say 'default' for every field). |
1268
|
|
|
|
|
|
|
|
1269
|
|
|
|
|
|
|
$form->process( defaults => { foo => 'this_foo', bar => 'this_bar' }, ... ); |
1270
|
|
|
|
|
|
|
|
1271
|
|
|
|
|
|
|
=head3 active/inactive |
1272
|
|
|
|
|
|
|
|
1273
|
|
|
|
|
|
|
A field can be marked 'inactive' and set to active at new or process time |
1274
|
|
|
|
|
|
|
by specifying the field name in the 'active' array: |
1275
|
|
|
|
|
|
|
|
1276
|
|
|
|
|
|
|
has_field 'foo' => ( type => 'Text', inactive => 1 ); |
1277
|
|
|
|
|
|
|
... |
1278
|
|
|
|
|
|
|
my $form = MyApp::Form->new( active => ['foo'] ); |
1279
|
|
|
|
|
|
|
... |
1280
|
|
|
|
|
|
|
$form->process( active => ['foo'] ); |
1281
|
|
|
|
|
|
|
|
1282
|
|
|
|
|
|
|
Or a field can be a normal active field and set to inactive at new or process |
1283
|
|
|
|
|
|
|
time: |
1284
|
|
|
|
|
|
|
|
1285
|
|
|
|
|
|
|
has_field 'bar'; |
1286
|
|
|
|
|
|
|
... |
1287
|
|
|
|
|
|
|
my $form = MyApp::Form->new( inactive => ['foo'] ); |
1288
|
|
|
|
|
|
|
... |
1289
|
|
|
|
|
|
|
$form->process( inactive => ['foo'] ); |
1290
|
|
|
|
|
|
|
|
1291
|
|
|
|
|
|
|
Fields specified as active/inactive on new will have the form's inactive/active |
1292
|
|
|
|
|
|
|
arrayref cleared and the field's inactive flag set appropriately, so that |
1293
|
|
|
|
|
|
|
the state will be effective for the life of the form object. Fields specified as |
1294
|
|
|
|
|
|
|
active/inactive on 'process' will have the field's '_active' flag set for the life |
1295
|
|
|
|
|
|
|
of the request (the _active flag will be cleared when the form is cleared). |
1296
|
|
|
|
|
|
|
|
1297
|
|
|
|
|
|
|
The 'sorted_fields' method returns only active fields, sorted according to the |
1298
|
|
|
|
|
|
|
'order' attribute. The 'fields' method returns all fields. |
1299
|
|
|
|
|
|
|
|
1300
|
|
|
|
|
|
|
foreach my $field ( $self->sorted_fields ) { ... } |
1301
|
|
|
|
|
|
|
|
1302
|
|
|
|
|
|
|
You can test whether a field is active by using the field 'is_active' and 'is_inactive' |
1303
|
|
|
|
|
|
|
methods. |
1304
|
|
|
|
|
|
|
|
1305
|
|
|
|
|
|
|
=head3 field_name_space |
1306
|
|
|
|
|
|
|
|
1307
|
|
|
|
|
|
|
Use to look for field during form construction. If a field is not found |
1308
|
|
|
|
|
|
|
with the field_name_space (or HTML::FormHandler/HTML::FormHandlerX), |
1309
|
|
|
|
|
|
|
the 'type' must start with a '+' and be the complete package name. |
1310
|
|
|
|
|
|
|
|
1311
|
|
|
|
|
|
|
=head3 fields |
1312
|
|
|
|
|
|
|
|
1313
|
|
|
|
|
|
|
The array of fields, objects of L<HTML::FormHandler::Field> or its subclasses. |
1314
|
|
|
|
|
|
|
A compound field will itself have an array of fields, |
1315
|
|
|
|
|
|
|
so this is a tree structure. |
1316
|
|
|
|
|
|
|
|
1317
|
|
|
|
|
|
|
=head3 sorted_fields |
1318
|
|
|
|
|
|
|
|
1319
|
|
|
|
|
|
|
Returns those fields from the fields array which are currently active. This |
1320
|
|
|
|
|
|
|
is the method that returns the fields that are looped through when rendering. |
1321
|
|
|
|
|
|
|
|
1322
|
|
|
|
|
|
|
=head3 field($name), subfield($name) |
1323
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
'field' is the method that is usually called to access a field: |
1325
|
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
my $title = $form->field('title')->value; |
1327
|
|
|
|
|
|
|
[% f = form.field('title') %] |
1328
|
|
|
|
|
|
|
|
1329
|
|
|
|
|
|
|
my $city = $form->field('addresses.0.city')->value; |
1330
|
|
|
|
|
|
|
|
1331
|
|
|
|
|
|
|
Pass a second true value to die on errors. |
1332
|
|
|
|
|
|
|
|
1333
|
|
|
|
|
|
|
Since fields are searched for using the form as a base, if you want to find |
1334
|
|
|
|
|
|
|
a sub field in a compound field method, the 'subfield' method may be more |
1335
|
|
|
|
|
|
|
useful, since you can search starting at the current field. The 'chained' |
1336
|
|
|
|
|
|
|
method also works: |
1337
|
|
|
|
|
|
|
|
1338
|
|
|
|
|
|
|
-- in a compound field -- |
1339
|
|
|
|
|
|
|
$self->field('media.caption'); # fails |
1340
|
|
|
|
|
|
|
$self->field('media')->field('caption'); # works |
1341
|
|
|
|
|
|
|
$self->subfield('media.caption'); # works |
1342
|
|
|
|
|
|
|
|
1343
|
|
|
|
|
|
|
=head2 Constraints and validation |
1344
|
|
|
|
|
|
|
|
1345
|
|
|
|
|
|
|
Most validation is performed on a per-field basis, and there are a number |
1346
|
|
|
|
|
|
|
of different places in which validation can be performed. |
1347
|
|
|
|
|
|
|
|
1348
|
|
|
|
|
|
|
See also L<HTML::FormHandler::Manual::Validation>. |
1349
|
|
|
|
|
|
|
|
1350
|
|
|
|
|
|
|
=head3 Form class validation for individual fields |
1351
|
|
|
|
|
|
|
|
1352
|
|
|
|
|
|
|
You can define a method in your form class to perform validation on a field. |
1353
|
|
|
|
|
|
|
This method is the equivalent of the field class validate method except it is |
1354
|
|
|
|
|
|
|
in the form class, so you might use this |
1355
|
|
|
|
|
|
|
validation method if you don't want to create a field subclass. |
1356
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
It has access to the form ($self) and the field. |
1358
|
|
|
|
|
|
|
This method is called after the field class 'validate' method, and is not |
1359
|
|
|
|
|
|
|
called if the value for the field is empty ('', undef). (If you want an |
1360
|
|
|
|
|
|
|
error message when the field is empty, use the 'required' flag and message |
1361
|
|
|
|
|
|
|
or the form 'validate' method.) |
1362
|
|
|
|
|
|
|
The name of this method can be set with 'set_validate' on the field. The |
1363
|
|
|
|
|
|
|
default is 'validate_' plus the field name: |
1364
|
|
|
|
|
|
|
|
1365
|
|
|
|
|
|
|
sub validate_testfield { my ( $self, $field ) = @_; ... } |
1366
|
|
|
|
|
|
|
|
1367
|
|
|
|
|
|
|
If the field name has dots they should be replaced with underscores. |
1368
|
|
|
|
|
|
|
|
1369
|
|
|
|
|
|
|
Note that you can also provide a coderef which will be a method on the field: |
1370
|
|
|
|
|
|
|
|
1371
|
|
|
|
|
|
|
has_field 'foo' => ( validate_method => \&validate_foo ); |
1372
|
|
|
|
|
|
|
|
1373
|
|
|
|
|
|
|
=head3 validate |
1374
|
|
|
|
|
|
|
|
1375
|
|
|
|
|
|
|
This is a form method that is useful for cross checking values after they have |
1376
|
|
|
|
|
|
|
been saved as their final validated value, and for performing more complex |
1377
|
|
|
|
|
|
|
dependency validation. It is called after all other field validation is done, |
1378
|
|
|
|
|
|
|
and whether or not validation has succeeded, so it has access to the |
1379
|
|
|
|
|
|
|
post-validation values of all the fields. |
1380
|
|
|
|
|
|
|
|
1381
|
|
|
|
|
|
|
This is the best place to do validation checks that depend on the values of |
1382
|
|
|
|
|
|
|
more than one field. |
1383
|
|
|
|
|
|
|
|
1384
|
|
|
|
|
|
|
=head2 Accessing errors |
1385
|
|
|
|
|
|
|
|
1386
|
|
|
|
|
|
|
Also see L<HTML::FormHandler::Manual::Errors>. |
1387
|
|
|
|
|
|
|
|
1388
|
|
|
|
|
|
|
Set an error in a field with C<< $field->add_error('some error string'); >>. |
1389
|
|
|
|
|
|
|
Set a form error not tied to a specific field with |
1390
|
|
|
|
|
|
|
C<< $self->add_form_error('another error string'); >>. |
1391
|
|
|
|
|
|
|
The 'add_error' and 'add_form_error' methods call localization. If you |
1392
|
|
|
|
|
|
|
want to skip localization for a particular error, you can use 'push_errors' |
1393
|
|
|
|
|
|
|
or 'push_form_errors' instead. |
1394
|
|
|
|
|
|
|
|
1395
|
|
|
|
|
|
|
has_errors - returns true or false |
1396
|
|
|
|
|
|
|
error_fields - returns list of fields with errors |
1397
|
|
|
|
|
|
|
errors - returns array of error messages for the entire form |
1398
|
|
|
|
|
|
|
num_errors - number of errors in form |
1399
|
|
|
|
|
|
|
|
1400
|
|
|
|
|
|
|
Each field has an array of error messages. (errors, has_errors, num_errors, |
1401
|
|
|
|
|
|
|
clear_errors) |
1402
|
|
|
|
|
|
|
|
1403
|
|
|
|
|
|
|
$form->field('title')->errors; |
1404
|
|
|
|
|
|
|
|
1405
|
|
|
|
|
|
|
Compound fields also have an array of error_fields. |
1406
|
|
|
|
|
|
|
|
1407
|
|
|
|
|
|
|
=head2 Clear form state |
1408
|
|
|
|
|
|
|
|
1409
|
|
|
|
|
|
|
The clear method is called at the beginning of 'process' if the form |
1410
|
|
|
|
|
|
|
object is reused, such as when it is persistent in a Moose attribute, |
1411
|
|
|
|
|
|
|
or in tests. If you add other attributes to your form that are set on |
1412
|
|
|
|
|
|
|
each request, you may need to clear those yourself. |
1413
|
|
|
|
|
|
|
|
1414
|
|
|
|
|
|
|
If you do not call the form's 'process' method on a persistent form, |
1415
|
|
|
|
|
|
|
such as in a REST controller's non-POST method, or if you only call |
1416
|
|
|
|
|
|
|
process when the form is posted, you will also need to call C<< $form->clear >>. |
1417
|
|
|
|
|
|
|
|
1418
|
|
|
|
|
|
|
The 'run' method which returns a result object always performs 'clear', to |
1419
|
|
|
|
|
|
|
keep the form object clean. |
1420
|
|
|
|
|
|
|
|
1421
|
|
|
|
|
|
|
=head2 Miscellaneous attributes |
1422
|
|
|
|
|
|
|
|
1423
|
|
|
|
|
|
|
=head3 name |
1424
|
|
|
|
|
|
|
|
1425
|
|
|
|
|
|
|
The form's name. Useful for multiple forms. Used for the form element 'id'. |
1426
|
|
|
|
|
|
|
When 'html_prefix' is set it is used to construct the field 'id' |
1427
|
|
|
|
|
|
|
and 'name'. The default is "form" + a one to three digit random number. |
1428
|
|
|
|
|
|
|
Because the HTML standards have flip-flopped on whether the HTML |
1429
|
|
|
|
|
|
|
form element can contain a 'name' attribute, please set a name attribute |
1430
|
|
|
|
|
|
|
using 'form_element_attr'. |
1431
|
|
|
|
|
|
|
|
1432
|
|
|
|
|
|
|
=head3 init_object |
1433
|
|
|
|
|
|
|
|
1434
|
|
|
|
|
|
|
An 'init_object' may be used instead of the 'item' to pre-populate the values |
1435
|
|
|
|
|
|
|
in the form. This can be useful when populating a form from default values |
1436
|
|
|
|
|
|
|
stored in a similar but different object than the one the form is creating. |
1437
|
|
|
|
|
|
|
The 'init_object' should be either a hash or the same type of object that |
1438
|
|
|
|
|
|
|
the model uses (a DBIx::Class row for the DBIC model). It can be set in a |
1439
|
|
|
|
|
|
|
variety of ways: |
1440
|
|
|
|
|
|
|
|
1441
|
|
|
|
|
|
|
my $form = MyApp::Form->new( init_object => { .... } ); |
1442
|
|
|
|
|
|
|
$form->process( init_object => {...}, ... ); |
1443
|
|
|
|
|
|
|
has '+init_object' => ( default => sub { { .... } } ); |
1444
|
|
|
|
|
|
|
sub init_object { my $self = shift; .... } |
1445
|
|
|
|
|
|
|
|
1446
|
|
|
|
|
|
|
The method version is useful if the organization of data in your form does |
1447
|
|
|
|
|
|
|
not map to an existing or database object in an automatic way, and you need |
1448
|
|
|
|
|
|
|
to create a different type of object for initialization. (You might also |
1449
|
|
|
|
|
|
|
want to do 'update_model' yourself.) |
1450
|
|
|
|
|
|
|
|
1451
|
|
|
|
|
|
|
Also see the 'use_init_obj_over_item' and the 'use_init_obj_when_no_accessor_in_item' |
1452
|
|
|
|
|
|
|
flags, if you want to provide both an item and an init_object, and use the |
1453
|
|
|
|
|
|
|
values from the init_object. |
1454
|
|
|
|
|
|
|
|
1455
|
|
|
|
|
|
|
The 'use_init_obj_when_no_accessor_in_item' flag is particularly useful |
1456
|
|
|
|
|
|
|
when some of the fields in your form come from the database and some |
1457
|
|
|
|
|
|
|
are process or environment type flags that are not in the database. You |
1458
|
|
|
|
|
|
|
can provide defaults from both a database row and an 'init_object. |
1459
|
|
|
|
|
|
|
|
1460
|
|
|
|
|
|
|
=head3 ctx |
1461
|
|
|
|
|
|
|
|
1462
|
|
|
|
|
|
|
Place to store application context for your use in your form's methods. |
1463
|
|
|
|
|
|
|
|
1464
|
|
|
|
|
|
|
=head3 language_handle |
1465
|
|
|
|
|
|
|
|
1466
|
|
|
|
|
|
|
See 'language_handle' and '_build_language_handle' in |
1467
|
|
|
|
|
|
|
L<HTML::FormHandler::TraitFor::I18N>. |
1468
|
|
|
|
|
|
|
|
1469
|
|
|
|
|
|
|
=head3 dependency |
1470
|
|
|
|
|
|
|
|
1471
|
|
|
|
|
|
|
Arrayref of arrayrefs of fields. If one of a group of fields has a |
1472
|
|
|
|
|
|
|
value, then all of the group are set to 'required'. |
1473
|
|
|
|
|
|
|
|
1474
|
|
|
|
|
|
|
has '+dependency' => ( default => sub { [ |
1475
|
|
|
|
|
|
|
['street', 'city', 'state', 'zip' ],] } |
1476
|
|
|
|
|
|
|
); |
1477
|
|
|
|
|
|
|
|
1478
|
|
|
|
|
|
|
=head2 Flags |
1479
|
|
|
|
|
|
|
|
1480
|
|
|
|
|
|
|
=head3 validated, is_valid |
1481
|
|
|
|
|
|
|
|
1482
|
|
|
|
|
|
|
Flag that indicates if form has been validated. You might want to use |
1483
|
|
|
|
|
|
|
this flag if you're doing something in between process and returning, |
1484
|
|
|
|
|
|
|
such as setting a stash key. ('is_valid' is a synonym for this flag) |
1485
|
|
|
|
|
|
|
|
1486
|
|
|
|
|
|
|
$form->process( ... ); |
1487
|
|
|
|
|
|
|
$c->stash->{...} = ...; |
1488
|
|
|
|
|
|
|
return unless $form->validated; |
1489
|
|
|
|
|
|
|
|
1490
|
|
|
|
|
|
|
=head3 ran_validation |
1491
|
|
|
|
|
|
|
|
1492
|
|
|
|
|
|
|
Flag to indicate that validation has been run. This flag will be |
1493
|
|
|
|
|
|
|
false when the form is initially loaded and displayed, since |
1494
|
|
|
|
|
|
|
validation is not run until FormHandler has params to validate. |
1495
|
|
|
|
|
|
|
|
1496
|
|
|
|
|
|
|
=head3 verbose, dump, peek |
1497
|
|
|
|
|
|
|
|
1498
|
|
|
|
|
|
|
Flag to dump diagnostic information. See 'dump_fields' and |
1499
|
|
|
|
|
|
|
'dump_validated'. 'Peek' can be useful in diagnosing bugs. |
1500
|
|
|
|
|
|
|
It will dump a brief listing of the fields and results. |
1501
|
|
|
|
|
|
|
|
1502
|
|
|
|
|
|
|
$form->process( ... ); |
1503
|
|
|
|
|
|
|
$form->peek; |
1504
|
|
|
|
|
|
|
|
1505
|
|
|
|
|
|
|
=head3 html_prefix |
1506
|
|
|
|
|
|
|
|
1507
|
|
|
|
|
|
|
Flag to indicate that the form name is used as a prefix for fields |
1508
|
|
|
|
|
|
|
in an HTML form. Useful for multiple forms |
1509
|
|
|
|
|
|
|
on the same HTML page. The prefix is stripped off of the fields |
1510
|
|
|
|
|
|
|
before creating the internal field name, and added back in when |
1511
|
|
|
|
|
|
|
returning a parameter hash from the 'fif' method. For example, |
1512
|
|
|
|
|
|
|
the field name in the HTML form could be "book.borrower", and |
1513
|
|
|
|
|
|
|
the field name in the FormHandler form (and the database column) |
1514
|
|
|
|
|
|
|
would be just "borrower". |
1515
|
|
|
|
|
|
|
|
1516
|
|
|
|
|
|
|
has '+name' => ( default => 'book' ); |
1517
|
|
|
|
|
|
|
has '+html_prefix' => ( default => 1 ); |
1518
|
|
|
|
|
|
|
|
1519
|
|
|
|
|
|
|
Also see the Field attribute "html_name", a convenience function which |
1520
|
|
|
|
|
|
|
will return the form name + "." + field full_name |
1521
|
|
|
|
|
|
|
|
1522
|
|
|
|
|
|
|
=head3 is_html5 |
1523
|
|
|
|
|
|
|
|
1524
|
|
|
|
|
|
|
Flag to indicate the fields will render using specialized attributes for html5. |
1525
|
|
|
|
|
|
|
Set to 0 by default. |
1526
|
|
|
|
|
|
|
|
1527
|
|
|
|
|
|
|
=head3 use_defaults_over_obj |
1528
|
|
|
|
|
|
|
|
1529
|
|
|
|
|
|
|
The 'normal' precedence is that if there is an accessor in the item/init_object |
1530
|
|
|
|
|
|
|
that value is used and not the 'default'. This flag makes the defaults of higher |
1531
|
|
|
|
|
|
|
precedence. Mainly useful if providing an empty row on create. |
1532
|
|
|
|
|
|
|
|
1533
|
|
|
|
|
|
|
=head3 use_init_obj_over_item |
1534
|
|
|
|
|
|
|
|
1535
|
|
|
|
|
|
|
If you are providing both an item and an init_object, and want the init_object |
1536
|
|
|
|
|
|
|
to be used for defaults instead of the item. |
1537
|
|
|
|
|
|
|
|
1538
|
|
|
|
|
|
|
=head2 For use in HTML |
1539
|
|
|
|
|
|
|
|
1540
|
|
|
|
|
|
|
form_element_attr - hashref for setting arbitrary HTML attributes |
1541
|
|
|
|
|
|
|
set in form with: sub build_form_element_attr {...} |
1542
|
|
|
|
|
|
|
form_element_class - arrayref for setting form tag class |
1543
|
|
|
|
|
|
|
form_wrapper_attr - hashref for form wrapper element attributes |
1544
|
|
|
|
|
|
|
set in form with: sub build_form_wrapper_attr {...} |
1545
|
|
|
|
|
|
|
form_wrapper_class - arrayref for setting wrapper class |
1546
|
|
|
|
|
|
|
do_form_wrapper - flag to wrap the form |
1547
|
|
|
|
|
|
|
http_method - For storing 'post' or 'get' |
1548
|
|
|
|
|
|
|
action - Store the form 'action' on submission. No default value. |
1549
|
|
|
|
|
|
|
uuid - generates a string containing an HTML field with UUID |
1550
|
|
|
|
|
|
|
form_tags - hashref of tags for use in rendering code |
1551
|
|
|
|
|
|
|
widget_tags - rendering tags to be transferred to fields |
1552
|
|
|
|
|
|
|
|
1553
|
|
|
|
|
|
|
Discouraged (use form_element_attr instead): |
1554
|
|
|
|
|
|
|
|
1555
|
|
|
|
|
|
|
style - adds a 'style' attribute to the form tag |
1556
|
|
|
|
|
|
|
enctype - Request enctype |
1557
|
|
|
|
|
|
|
|
1558
|
|
|
|
|
|
|
Note that the form tag contains an 'id' attribute which is set to the |
1559
|
|
|
|
|
|
|
form name. The standards have been flip-flopping over whether a 'name' |
1560
|
|
|
|
|
|
|
attribute is valid. It can be set with 'form_element_attr'. |
1561
|
|
|
|
|
|
|
|
1562
|
|
|
|
|
|
|
The rendering of the HTML attributes is done using the 'process_attrs' |
1563
|
|
|
|
|
|
|
function and the 'element_attributes' or 'wrapper_attributes' method, |
1564
|
|
|
|
|
|
|
which adds other attributes in for backward compatibility, and calls |
1565
|
|
|
|
|
|
|
the 'html_attributes' hook. |
1566
|
|
|
|
|
|
|
|
1567
|
|
|
|
|
|
|
For HTML attributes, there is a form method hook, 'html_attributes', |
1568
|
|
|
|
|
|
|
which can be used to customize/modify/localize form & field HTML attributes. |
1569
|
|
|
|
|
|
|
Types: element, wrapper, label, form_element, form_wrapper, checkbox_label |
1570
|
|
|
|
|
|
|
|
1571
|
|
|
|
|
|
|
sub html_attributes { |
1572
|
|
|
|
|
|
|
my ( $self, $obj, $type, $attrs, $result ) = @_; |
1573
|
|
|
|
|
|
|
|
1574
|
|
|
|
|
|
|
# obj is either form or field |
1575
|
|
|
|
|
|
|
$attr->{class} = 'label' if $type eq 'label'; |
1576
|
|
|
|
|
|
|
$attr->{placeholder} = $self->_localize($attr->{placeholder}) |
1577
|
|
|
|
|
|
|
if exists $attr->{placeholder}; |
1578
|
|
|
|
|
|
|
return $attr; |
1579
|
|
|
|
|
|
|
} |
1580
|
|
|
|
|
|
|
|
1581
|
|
|
|
|
|
|
Also see the documentation in L<HTML::FormHandler::Field> and in |
1582
|
|
|
|
|
|
|
L<HTML::FormHandler::Manual::Rendering>. |
1583
|
|
|
|
|
|
|
|
1584
|
|
|
|
|
|
|
=head1 SUPPORT |
1585
|
|
|
|
|
|
|
|
1586
|
|
|
|
|
|
|
IRC: |
1587
|
|
|
|
|
|
|
|
1588
|
|
|
|
|
|
|
Join #formhandler on irc.perl.org |
1589
|
|
|
|
|
|
|
|
1590
|
|
|
|
|
|
|
Mailing list: |
1591
|
|
|
|
|
|
|
|
1592
|
|
|
|
|
|
|
http://groups.google.com/group/formhandler |
1593
|
|
|
|
|
|
|
|
1594
|
|
|
|
|
|
|
Code repository: |
1595
|
|
|
|
|
|
|
|
1596
|
|
|
|
|
|
|
http://github.com/gshank/html-formhandler/tree/master |
1597
|
|
|
|
|
|
|
|
1598
|
|
|
|
|
|
|
Bug tracker: |
1599
|
|
|
|
|
|
|
|
1600
|
|
|
|
|
|
|
https://rt.cpan.org/Dist/Display.html?Name=HTML-FormHandler |
1601
|
|
|
|
|
|
|
|
1602
|
|
|
|
|
|
|
=head1 SEE ALSO |
1603
|
|
|
|
|
|
|
|
1604
|
|
|
|
|
|
|
L<HTML::FormHandler::Manual> |
1605
|
|
|
|
|
|
|
|
1606
|
|
|
|
|
|
|
L<HTML::FormHandler::Manual::Tutorial> |
1607
|
|
|
|
|
|
|
|
1608
|
|
|
|
|
|
|
L<HTML::FormHandler::Manual::Intro> |
1609
|
|
|
|
|
|
|
|
1610
|
|
|
|
|
|
|
L<HTML::FormHandler::Manual::Templates> |
1611
|
|
|
|
|
|
|
|
1612
|
|
|
|
|
|
|
L<HTML::FormHandler::Manual::Cookbook> |
1613
|
|
|
|
|
|
|
|
1614
|
|
|
|
|
|
|
L<HTML::FormHandler::Manual::Rendering> |
1615
|
|
|
|
|
|
|
|
1616
|
|
|
|
|
|
|
L<HTML::FormHandler::Manual::Reference> |
1617
|
|
|
|
|
|
|
|
1618
|
|
|
|
|
|
|
L<HTML::FormHandler::Field> |
1619
|
|
|
|
|
|
|
|
1620
|
|
|
|
|
|
|
L<HTML::FormHandler::Model::DBIC> |
1621
|
|
|
|
|
|
|
|
1622
|
|
|
|
|
|
|
L<HTML::FormHandler::Render::Simple> |
1623
|
|
|
|
|
|
|
|
1624
|
|
|
|
|
|
|
L<HTML::FormHandler::Render::Table> |
1625
|
|
|
|
|
|
|
|
1626
|
|
|
|
|
|
|
L<HTML::FormHandler::Moose> |
1627
|
|
|
|
|
|
|
|
1628
|
|
|
|
|
|
|
=head1 CONTRIBUTORS |
1629
|
|
|
|
|
|
|
|
1630
|
|
|
|
|
|
|
gshank: Gerda Shank E<lt>gshank@cpan.orgE<gt> |
1631
|
|
|
|
|
|
|
|
1632
|
|
|
|
|
|
|
zby: Zbigniew Lukasiak E<lt>zby@cpan.orgE<gt> |
1633
|
|
|
|
|
|
|
|
1634
|
|
|
|
|
|
|
t0m: Tomas Doran E<lt>bobtfish@bobtfish.netE<gt> |
1635
|
|
|
|
|
|
|
|
1636
|
|
|
|
|
|
|
augensalat: Bernhard Graf E<lt>augensalat@gmail.comE<gt> |
1637
|
|
|
|
|
|
|
|
1638
|
|
|
|
|
|
|
cubuanic: Oleg Kostyuk E<lt>cub.uanic@gmail.comE<gt> |
1639
|
|
|
|
|
|
|
|
1640
|
|
|
|
|
|
|
rafl: Florian Ragwitz E<lt>rafl@debian.orgE<gt> |
1641
|
|
|
|
|
|
|
|
1642
|
|
|
|
|
|
|
mazpe: Lester Ariel Mesa |
1643
|
|
|
|
|
|
|
|
1644
|
|
|
|
|
|
|
dew: Dan Thomas |
1645
|
|
|
|
|
|
|
|
1646
|
|
|
|
|
|
|
koki: Klaus Ita |
1647
|
|
|
|
|
|
|
|
1648
|
|
|
|
|
|
|
jnapiorkowski: John Napiorkowski |
1649
|
|
|
|
|
|
|
|
1650
|
|
|
|
|
|
|
lestrrat: Daisuke Maki |
1651
|
|
|
|
|
|
|
|
1652
|
|
|
|
|
|
|
hobbs: Andrew Rodland |
1653
|
|
|
|
|
|
|
|
1654
|
|
|
|
|
|
|
Andy Clayton |
1655
|
|
|
|
|
|
|
|
1656
|
|
|
|
|
|
|
boghead: Bryan Beeley |
1657
|
|
|
|
|
|
|
|
1658
|
|
|
|
|
|
|
Csaba Hetenyi |
1659
|
|
|
|
|
|
|
|
1660
|
|
|
|
|
|
|
Eisuke Oishi |
1661
|
|
|
|
|
|
|
|
1662
|
|
|
|
|
|
|
Lian Wan Situ |
1663
|
|
|
|
|
|
|
|
1664
|
|
|
|
|
|
|
Murray |
1665
|
|
|
|
|
|
|
|
1666
|
|
|
|
|
|
|
Nick Logan |
1667
|
|
|
|
|
|
|
|
1668
|
|
|
|
|
|
|
Vladimir Timofeev |
1669
|
|
|
|
|
|
|
|
1670
|
|
|
|
|
|
|
diegok: Diego Kuperman |
1671
|
|
|
|
|
|
|
|
1672
|
|
|
|
|
|
|
ijw: Ian Wells |
1673
|
|
|
|
|
|
|
|
1674
|
|
|
|
|
|
|
amiri: Amiri Barksdale |
1675
|
|
|
|
|
|
|
|
1676
|
|
|
|
|
|
|
ozum: Ozum Eldogan |
1677
|
|
|
|
|
|
|
|
1678
|
|
|
|
|
|
|
lukast: Lukas Thiemeier |
1679
|
|
|
|
|
|
|
|
1680
|
|
|
|
|
|
|
Initially based on the source code of L<Form::Processor> by Bill Moseley |
1681
|
|
|
|
|
|
|
|
1682
|
|
|
|
|
|
|
=head1 AUTHOR |
1683
|
|
|
|
|
|
|
|
1684
|
|
|
|
|
|
|
FormHandler Contributors - see HTML::FormHandler |
1685
|
|
|
|
|
|
|
|
1686
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
1687
|
|
|
|
|
|
|
|
1688
|
|
|
|
|
|
|
This software is copyright (c) 2016 by Gerda Shank. |
1689
|
|
|
|
|
|
|
|
1690
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
1691
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
1692
|
|
|
|
|
|
|
|
1693
|
|
|
|
|
|
|
=cut |