File Coverage

blib/lib/Form/Tiny/FieldDefinition.pm
Criterion Covered Total %
statement 96 96 100.0
branch 41 44 93.1
condition 18 24 75.0
subroutine 20 20 100.0
pod 2 6 33.3
total 177 190 93.1


line stmt bran cond sub pod time code
1             package Form::Tiny::FieldDefinition;
2             $Form::Tiny::FieldDefinition::VERSION = '2.26';
3 53     53   3336 use v5.10;
  53         197  
4 53     53   311 use strict;
  53         135  
  53         1581  
5 53     53   263 use warnings;
  53         138  
  53         2630  
6 53     53   453 use Moo;
  53         147  
  53         541  
7 53     53   22661 use Types::Standard qw(Enum Bool HasMethods CodeRef InstanceOf HashRef);
  53         185  
  53         440  
8 53     53   157576 use Types::Common::String qw(NonEmptySimpleStr);
  53         2170175  
  53         605  
9 53     53   72846 use Types::TypeTiny qw(StringLike);
  53         122  
  53         391  
10 53     53   32138 use Carp qw(croak);
  53         140  
  53         4390  
11 53     53   384 use Scalar::Util qw(blessed);
  53         111  
  53         2680  
12 53     53   26467 use Data::Dumper;
  53         406751  
  53         4707  
13              
14 53     53   437 use Form::Tiny::Utils qw(try has_form_meta);
  53         118  
  53         3527  
15 53     53   710 use Form::Tiny::Error;
  53         115  
  53         1595  
16 53     53   18674 use Form::Tiny::Path;
  53         221  
  53         74521  
17              
18             has 'name' => (
19             is => 'ro',
20             isa => NonEmptySimpleStr,
21             required => 1,
22             );
23              
24             has 'name_path' => (
25             is => 'ro',
26             isa => InstanceOf ['Form::Tiny::Path'],
27             reader => 'get_name_path',
28             init_arg => undef,
29             lazy => 1,
30             default => sub { Form::Tiny::Path->from_name(shift->name) },
31             );
32              
33             has 'required' => (
34             is => 'ro',
35             isa => Enum [0, 1, 'soft', 'hard'],
36             writer => 'set_required',
37             default => sub { 0 },
38             );
39              
40             has 'type' => (
41             is => 'ro',
42             isa => HasMethods ['validate', 'check'],
43             writer => 'set_type',
44             predicate => 'has_type',
45             );
46              
47             has 'addons' => (
48             is => 'ro',
49             writer => 'set_addons',
50             isa => HashRef,
51             default => sub { {} },
52             init_arg => undef,
53             );
54              
55             has 'coerce' => (
56             is => 'ro',
57             isa => Bool | CodeRef,
58             writer => 'set_coercion',
59             default => sub { 0 },
60             );
61              
62             has 'adjust' => (
63             is => 'ro',
64             isa => CodeRef,
65             predicate => 'is_adjusted',
66             writer => 'set_adjustment',
67             );
68              
69             has 'default' => (
70             is => 'ro',
71             isa => CodeRef,
72             writer => 'set_default',
73             predicate => 'has_default',
74             );
75              
76             has 'message' => (
77             is => 'ro',
78             isa => StringLike,
79             writer => 'set_message',
80             predicate => 'has_message',
81             );
82              
83             has 'data' => (
84             is => 'ro',
85             writer => 'set_data',
86             predicate => 'has_data',
87             );
88              
89             has '_subform' => (
90             is => 'ro',
91             isa => Bool,
92             reader => 'is_subform',
93             lazy => 1,
94             default => sub { $_[0]->has_type && has_form_meta($_[0]->type) },
95             init_arg => undef,
96             );
97              
98             sub BUILD
99             {
100 300     300 0 18869 my ($self, $args) = @_;
101              
102 300 100 100     1699 if ($self->coerce && ref $self->coerce ne 'CODE') {
103              
104             # checks for coercion == 1
105 16         78 my $t = $self->type;
106 16 100 33     612 croak 'type doesn\'t provide coercion'
      66        
      100        
107             if !$self->has_type
108             || !($t->can('coerce') && $t->can('has_coercion') && $t->has_coercion);
109             }
110              
111 298 100       3146 if ($self->has_default) {
112              
113             croak 'default value for an array field is unsupported'
114 15 100       30 if scalar grep { $_ } @{$self->get_name_path->meta_arrays};
  22         588  
  15         341  
115             }
116             }
117              
118             sub hard_required
119             {
120 31     31 1 80 my ($self) = @_;
121              
122 31   100     272 return $self->required eq '1' || $self->required eq 'hard';
123             }
124              
125             sub get_coerced
126             {
127 358     358 0 1733 my ($self, $form, $value) = @_;
128 358         1001 my $coerce = $self->coerce;
129              
130 358 100       908 if ($coerce) {
131             my $error = try sub {
132 62 100   62   147 if (ref $coerce eq 'CODE') {
133 29         72 $value = $coerce->($form, $value);
134             }
135             else {
136 33         129 $value = $self->type->coerce($value);
137             }
138 62         340 };
139              
140 62 100       305 if ($error) {
141 3 50       90 $form->add_error(
142             Form::Tiny::Error::DoesNotValidate->new(
143             {
144             field_def => $self,
145             error => $self->has_message ? $self->message : $error,
146             }
147             )
148             );
149             }
150             }
151              
152 358         979 return $value;
153             }
154              
155             sub get_adjusted
156             {
157 281     281 0 639 my ($self, $form, $value) = @_;
158              
159             # NOTE: subform must be already validated at this stage
160 281 100       7215 $value = $self->type->fields
161             if $self->is_subform;
162              
163 281 100       5518 return $value unless $self->is_adjusted;
164 27         106 return $self->adjust->($form, $value);
165             }
166              
167             sub get_default
168             {
169 22     22 0 125 my ($self, $form) = @_;
170              
171 22 50       167 croak 'no default value set but was requested'
172             unless $self->has_default;
173              
174 22         78 my $default = $self->default->($form);
175 22 100       530 if ($self->is_subform) {
176 2         72 my $subform = $self->type;
177 2 100       15 croak 'subform default input is not valid. ' . Data::Dumper->Dump([$subform->errors_hash], ['errors'])
178             unless $subform->check($default);
179              
180 1         4 $default = $subform->fields;
181             }
182              
183 21         461 return $default;
184             }
185              
186             sub validate
187             {
188 358     358 1 765 my ($self, $form, $value) = @_;
189              
190 358         701 my @errors;
191              
192 358 100       1336 if ($self->has_type) {
193 213 100       589 if ($self->has_message) {
194 8 100       60 push @errors, $self->message
195             if !$self->type->check($value);
196             }
197             else {
198 205         906 my $error = $self->type->validate($value);
199 205 100       10737 push @errors, $error
200             if defined $error;
201             }
202             }
203              
204 358 100 100     2081 if (@errors == 0 && (my $validators = $self->addons->{validators})) {
205 5         11 for my $validator (@{$validators}) {
  5         16  
206 9         25 my ($message, $code) = @{$validator};
  9         25  
207              
208 9 100       33 if (!$code->($form, $value)) {
209 4         24 push @errors, $message;
210             }
211             }
212             }
213              
214 358         3811 for my $error (@errors) {
215 78 100 66     523 if (ref $error eq 'ARRAY' && $self->is_subform) {
216 10         109 foreach my $exception (@$error) {
217 10         23 my $class = 'Form::Tiny::Error::DoesNotValidate';
218 10 50 33     79 if (defined blessed $exception && $exception->isa('Form::Tiny::Error')) {
219 10         40 $class = 'Form::Tiny::Error::NestedFormError';
220              
221 10         239 my $path = $self->get_name_path;
222 10 100       135 $path = $path->clone->append_path(Form::Tiny::Path->from_name($exception->field))
223             if defined $exception->field;
224              
225 10         71 $exception->set_field($path->join);
226             }
227              
228             $form->add_error(
229 10         581 $class->new(
230             field_def => $self,
231             error => $exception,
232             )
233             );
234             }
235             }
236             else {
237 68         2168 $form->add_error(
238             Form::Tiny::Error::DoesNotValidate->new(
239             {
240             field_def => $self,
241             error => $error,
242             }
243             )
244             );
245             }
246             }
247              
248 358         1283 return @errors == 0;
249             }
250              
251             1;
252              
253             __END__