File Coverage

blib/lib/Form/Tiny/FieldDefinition.pm
Criterion Covered Total %
statement 93 93 100.0
branch 40 44 90.9
condition 18 24 75.0
subroutine 19 19 100.0
pod 2 6 33.3
total 172 186 92.4


line stmt bran cond sub pod time code
1             package Form::Tiny::FieldDefinition;
2             $Form::Tiny::FieldDefinition::VERSION = '2.21';
3 52     52   3249 use v5.10;
  52         198  
4 52     52   298 use strict;
  52         101  
  52         1134  
5 52     52   295 use warnings;
  52         126  
  52         1408  
6 52     52   297 use Moo;
  52         190  
  52         347  
7 52     52   17635 use Types::Standard qw(Enum Bool HasMethods CodeRef InstanceOf HashRef);
  52         147  
  52         1326  
8 52     52   142512 use Types::Common::String qw(NonEmptySimpleStr);
  52         2910247  
  52         613  
9 52     52   56095 use Types::TypeTiny qw(StringLike);
  52         120  
  52         328  
10 52     52   27624 use Carp qw(croak);
  52         133  
  52         3265  
11 52     52   382 use Scalar::Util qw(blessed);
  52         159  
  52         2423  
12              
13 52     52   357 use Form::Tiny::Utils qw(try has_form_meta);
  52         128  
  52         2466  
14 52     52   784 use Form::Tiny::Error;
  52         131  
  52         1149  
15 52     52   22446 use Form::Tiny::Path;
  52         183  
  52         58963  
16              
17             has 'name' => (
18             is => 'ro',
19             isa => NonEmptySimpleStr,
20             required => 1,
21             );
22              
23             has 'name_path' => (
24             is => 'ro',
25             isa => InstanceOf ['Form::Tiny::Path'],
26             reader => 'get_name_path',
27             init_arg => undef,
28             lazy => 1,
29             default => sub { Form::Tiny::Path->from_name(shift->name) },
30             );
31              
32             has 'required' => (
33             is => 'ro',
34             isa => Enum [0, 1, 'soft', 'hard'],
35             writer => 'set_required',
36             default => sub { 0 },
37             );
38              
39             has 'type' => (
40             is => 'ro',
41             isa => HasMethods ['validate', 'check'],
42             writer => 'set_type',
43             predicate => 'has_type',
44             );
45              
46             has 'addons' => (
47             is => 'ro',
48             writer => 'set_addons',
49             isa => HashRef,
50             default => sub { {} },
51             init_arg => undef,
52             );
53              
54             has 'coerce' => (
55             is => 'ro',
56             isa => Bool | CodeRef,
57             writer => 'set_coercion',
58             default => sub { 0 },
59             );
60              
61             has 'adjust' => (
62             is => 'ro',
63             isa => CodeRef,
64             predicate => 'is_adjusted',
65             writer => 'set_adjustment',
66             );
67              
68             has 'default' => (
69             is => 'ro',
70             isa => CodeRef,
71             writer => 'set_default',
72             predicate => 'has_default',
73             );
74              
75             has 'message' => (
76             is => 'ro',
77             isa => StringLike,
78             writer => 'set_message',
79             predicate => 'has_message',
80             );
81              
82             has 'data' => (
83             is => 'ro',
84             writer => 'set_data',
85             predicate => 'has_data',
86             );
87              
88             has '_subform' => (
89             is => 'ro',
90             isa => Bool,
91             reader => 'is_subform',
92             lazy => 1,
93             default => sub { $_[0]->has_type && has_form_meta($_[0]->type) },
94             init_arg => undef,
95             );
96              
97             sub BUILD
98             {
99 296     296 0 14964 my ($self, $args) = @_;
100              
101 296 100 100     1350 if ($self->coerce && ref $self->coerce ne 'CODE') {
102              
103             # checks for coercion == 1
104 16         89 my $t = $self->type;
105 16 100 33     203 croak 'type doesn\'t provide coercion'
      66        
      100        
106             if !$self->has_type
107             || !($t->can('coerce') && $t->can('has_coercion') && $t->has_coercion);
108             }
109              
110 294 100       2289 if ($self->has_default) {
111              
112             croak 'default value for an array field is unsupported'
113 12 100       20 if scalar grep { $_ } @{$self->get_name_path->meta_arrays};
  19         457  
  12         227  
114             }
115             }
116              
117             sub hard_required
118             {
119 31     31 1 93 my ($self) = @_;
120              
121 31   100     254 return $self->required eq '1' || $self->required eq 'hard';
122             }
123              
124             sub get_coerced
125             {
126 352     352 0 749 my ($self, $form, $value) = @_;
127 352         797 my $coerce = $self->coerce;
128              
129 352 100       795 if ($coerce) {
130             my $error = try sub {
131 62 100   62   145 if (ref $coerce eq 'CODE') {
132 29         65 $value = $coerce->($form, $value);
133             }
134             else {
135 33         118 $value = $self->type->coerce($value);
136             }
137 62         346 };
138              
139 62 100       289 if ($error) {
140 3 50       77 $form->add_error(
141             Form::Tiny::Error::DoesNotValidate->new(
142             {
143             field => $self->name,
144             error => $self->has_message ? $self->message : $error,
145             }
146             )
147             );
148             }
149             }
150              
151 352         881 return $value;
152             }
153              
154             sub get_adjusted
155             {
156 281     281 0 567 my ($self, $form, $value) = @_;
157              
158             # NOTE: subform must be already validated at this stage
159 281 100       5512 $value = $self->type->fields
160             if $self->is_subform;
161              
162 281 100       4925 return $value unless $self->is_adjusted;
163 27         93 return $self->adjust->($form, $value);
164             }
165              
166             sub get_default
167             {
168 20     20 0 121 my ($self, $form) = @_;
169              
170 20 50       77 croak 'no default value set but was requested'
171             unless $self->has_default;
172              
173 20         75 my $default = $self->default->($form);
174 20 100       391 if ($self->is_subform) {
175 1         42 my $subform = $self->type;
176 1 50       6 croak 'subform default input is not valid'
177             unless $subform->check($default);
178              
179 1         17 $default = $subform->fields;
180             }
181              
182 20         390 return $default;
183             }
184              
185             sub validate
186             {
187 352     352 1 716 my ($self, $form, $value) = @_;
188              
189 352         537 my @errors;
190              
191 352 100       971 if ($self->has_type) {
192 207 100       545 if ($self->has_message) {
193 8 100       44 push @errors, $self->message
194             if !$self->type->check($value);
195             }
196             else {
197 199         645 my $error = $self->type->validate($value);
198 199 100       16395 push @errors, $error
199             if defined $error;
200             }
201             }
202              
203 352 100 100     1800 if (@errors == 0 && (my $validators = $self->addons->{validators})) {
204 5         10 for my $validator (@{$validators}) {
  5         12  
205 9         31 my ($message, $code) = @{$validator};
  9         23  
206              
207 9 100       38 if (!$code->($form, $value)) {
208 4         21 push @errors, $message;
209             }
210             }
211             }
212              
213 352         2914 for my $error (@errors) {
214 72 100 66     352 if (ref $error eq 'ARRAY' && $self->is_subform) {
215 7         75 foreach my $exception (@$error) {
216 7         16 my $class = 'Form::Tiny::Error::DoesNotValidate';
217 7 50 33     90 if (defined blessed $exception && $exception->isa('Form::Tiny::Error')) {
218 7         17 $class = 'Form::Tiny::Error::NestedFormError';
219              
220 7         124 my $path = $self->get_name_path;
221 7 100       109 $path = $path->clone->append_path(
222             $self->type->_ft_find_field($exception->field)->get_name_path
223             ) if defined $exception->field;
224              
225 7         33 $exception->set_field($path->join);
226             }
227              
228             $form->add_error(
229 7         420 $class->new(
230             field => $self->name,
231             error => $exception,
232             )
233             );
234             }
235             }
236             else {
237 65         1527 $form->add_error(
238             Form::Tiny::Error::DoesNotValidate->new(
239             {
240             field => $self->name,
241             error => $error,
242             }
243             )
244             );
245             }
246             }
247              
248 352         1177 return @errors == 0;
249             }
250              
251             1;
252              
253             __END__