File Coverage

blib/lib/Rose/HTML/Form/Field/DateTime.pm
Criterion Covered Total %
statement 59 61 96.7
branch 16 20 80.0
condition 5 6 83.3
subroutine 15 15 100.0
pod 4 6 66.6
total 99 108 91.6


line stmt bran cond sub pod time code
1             package Rose::HTML::Form::Field::DateTime;
2              
3 6     6   59 use strict;
  6         13  
  6         206  
4              
5 6     6   482 use Rose::HTML::Object::Errors qw(:field :date);
  6         16  
  6         62  
6              
7 6     6   585 use Rose::DateTime::Util();
  6         585779  
  6         125  
8 6     6   3086 use Rose::DateTime::Parser;
  6         11697  
  6         196  
9              
10 6     6   50 use base 'Rose::HTML::Form::Field::Text';
  6         18  
  6         2015  
11              
12             our $VERSION = '0.606';
13              
14             use Rose::Object::MakeMethods::Generic
15             (
16 6         42 'scalar --get_set_init' =>
17             [
18             'date_parser',
19             'output_format',
20             ]
21 6     6   49 );
  6         16  
22              
23             __PACKAGE__->add_required_html_attr(
24             {
25             size => 25,
26             });
27              
28 18     18 0 282 sub init_date_parser { Rose::DateTime::Parser->new() }
29              
30             sub time_zone
31             {
32 4     4 1 13 my($self) = shift;
33              
34 4         12 my $parser = $self->date_parser;
35              
36 4 50       45 return $parser->time_zone(@_) if($parser->can('time_zone'));
37 0         0 return undef;
38             }
39              
40             sub inflate_value
41             {
42 348     348 1 733 my($self, $date) = @_;
43              
44 348 100 66     1601 return undef unless(ref $date || (defined $date && length $date));
      100        
45              
46 178         308 my $dt;
47              
48 178         304 local $@;
49 178         352 eval { $dt = $self->date_parser->parse_datetime($date) };
  178         505  
50              
51 178         92143 return $dt;
52             }
53              
54 5     5 0 53 sub init_output_format { '%Y-%m-%d %I:%M:%S %p' }
55              
56             sub deflate_value
57             {
58 32     32 1 72 my($self, $date) = @_;
59 32 100       122 return $self->input_value_filtered unless($date);
60 23         149 return Rose::DateTime::Util::format_date($date, $self->output_format);
61             }
62              
63             sub validate
64             {
65 33     33 1 79 my($self) = shift;
66              
67 6     6   2036 no warnings 'uninitialized';
  6         19  
  6         1314  
68 33 100       111 if($self->input_value !~ /\S/)
69             {
70 9         60 my $ok = $self->SUPER::validate(@_);
71 9 50       32 return $ok unless($ok);
72             }
73              
74 33         156 my $date = $self->internal_value;
75              
76 33 100       160 if(UNIVERSAL::isa($date, 'DateTime'))
77             {
78 17 50       82 return $self->validate_with_validator($date) if($self->validator);
79 17         77 return 1;
80             }
81              
82 16 100       71 if($self->has_partial_value)
83             {
84 1         8 $self->add_error_id(FIELD_PARTIAL_VALUE);
85 1         11 return 0;
86             }
87              
88 15         136 my $input = $self->input_value_filtered;
89 6     6   55 no warnings 'uninitialized';
  6         12  
  6         860  
90 15 100       92 return 1 unless(length $input);
91              
92 7         20 $date = $self->date_parser->parse_datetime($input);
93              
94 7 50       307 unless(defined $date)
95             {
96             # XXX: Parser errors ar English-only right now...
97             # XXX: ...but it produces some horribly ugly errors.
98             #if($self->locale eq 'en')
99             #{
100             # $self->add_error($self->date_parser->error)
101             # if($self->date_parser->can('error'));
102             #}
103             #else
104             #{
105 7         79 $self->add_error_id(DATE_INVALID);
106             #}
107              
108 7         36 return 0;
109             }
110              
111 0           die "This should never be reached!";
112             }
113              
114             if(__PACKAGE__->localizer->auto_load_messages)
115             {
116             __PACKAGE__->localizer->load_all_messages;
117             }
118              
119 6     6   47 use utf8; # The __DATA__ section contains UTF-8 text
  6         27  
  6         42  
120              
121             1;
122              
123             __DATA__
124              
125             [% LOCALE en %]
126              
127             DATE_INVALID = "Invalid date."
128              
129             [% LOCALE de %]
130              
131             DATE_INVALID = "Ungültiges Datum."
132              
133             [% LOCALE fr %]
134              
135             DATE_INVALID = "Date invalide."
136              
137             [% LOCALE bg %]
138              
139             DATE_INVALID = "Невалидна дата."
140              
141             __END__
142              
143             =head1 NAME
144              
145             Rose::HTML::Form::Field::DateTime - Text field that inflates valid dates and times into L<DateTime> objects.
146              
147             =head1 SYNOPSIS
148              
149             $field =
150             Rose::HTML::Form::Field::DateTime->new(
151             label => 'Date',
152             name => 'date',
153             default => '12/31/2002 8pm');
154              
155             print $field->internal_value; # "2002-12-31T20:00:00"
156             print $field->output_value; # "2002-12-31 08:00:00 PM"
157              
158             $field->input_value('blah');
159              
160             # "Could not parse date: blah"
161             $field->validate or warn $field->error;
162              
163             $field->input_value('4/30/1980 5:30 p.m.');
164              
165             $dt = $field->internal_value; # DateTime object
166              
167             print $dt->hour; # 17
168             print $dt->day_name; # Wednesday
169              
170             print $field->html;
171             ...
172              
173             =head1 DESCRIPTION
174              
175             L<Rose::HTML::Form::Field::DateTime> is a subclass of L<Rose::HTML::Form::Field::Text> that allows only valid dates as input, which it then coerces to L<DateTime> objects. It overrides the L<validate()|Rose::HTML::Form::Field/validate>, L<inflate_value()|Rose::HTML::Form::Field/inflate_value>, and L<deflate_value()|Rose::HTML::Form::Field/deflate_value> methods of its parent class.
176              
177             Valid input is converted to the format "YYYY-MM-DD HH:MM:SS AM/PM" on output.
178              
179             =head1 OBJECT METHODS
180              
181             =over 4
182              
183             =item B<date_parser [PARSER]>
184              
185             Get or set the date parser object. This object must include a C<parse_datetime()> method that takes a single string as an argument and returns a L<DateTime> object, or undef if parsing fails.
186              
187             If the parser object has an C<error()> method, it will be called to set the error message after a failed parsing attempt.
188              
189             The parser object defaults to L<Rose::DateTime::Parser-E<gt>new()|Rose::DateTime::Parser/new>.
190              
191             =item B<output_format [FORMAT]>
192              
193             Get or set the format string passed to L<Rose::DateTime::Util>'s L<format_date|Rose::DateTime::Util/format_date> function in order to generate the field's output value. Defaults to "%Y-%m-%d %I:%M:%S %p"
194              
195             =item B<time_zone [TZ]>
196              
197             If the parser object has a L<time_zone()|/time_zone> method, this method simply calls it, passing all arguments. Otherwise, undef is returned.
198              
199             =back
200              
201             =head1 SEE ALSO
202              
203             Other examples of custom fields:
204              
205             =over 4
206              
207             =item L<Rose::HTML::Form::Field::Email>
208              
209             A text field that only accepts valid email addresses.
210              
211             =item L<Rose::HTML::Form::Field::Time>
212              
213             Uses inflate/deflate to coerce input into a fixed format.
214              
215             =item L<Rose::HTML::Form::Field::DateTime::Range>
216              
217             A compound field whose internal value consists of more than one object.
218              
219             =item L<Rose::HTML::Form::Field::PhoneNumber::US::Split>
220              
221             A simple compound field that coalesces multiple subfields into a single value.
222              
223             =item L<Rose::HTML::Form::Field::DateTime::Split::MonthDayYear>
224              
225             A compound field that uses inflate/deflate convert input from multiple subfields into a L<DateTime> object.
226              
227             =item L<Rose::HTML::Form::Field::DateTime::Split::MDYHMS>
228              
229             A compound field that includes other compound fields and uses inflate/deflate convert input from multiple subfields into a L<DateTime> object.
230              
231             =back
232              
233             =head1 AUTHOR
234              
235             John C. Siracusa (siracusa@gmail.com)
236              
237             =head1 LICENSE
238              
239             Copyright (c) 2010 by John C. Siracusa. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.