File Coverage

blib/lib/Rose/HTML/Form/Field/DateTime/Split/MDYHMS.pm
Criterion Covered Total %
statement 43 43 100.0
branch 11 12 91.6
condition 3 4 75.0
subroutine 13 13 100.0
pod 7 7 100.0
total 77 79 97.4


line stmt bran cond sub pod time code
1             package Rose::HTML::Form::Field::DateTime::Split::MDYHMS;
2              
3 5     5   6763 use strict;
  5         13  
  5         145  
4              
5 5     5   43 use Rose::DateTime::Util();
  5         14  
  5         105  
6              
7 5     5   605 use Rose::HTML::Form::Field::DateTime::Split::MonthDayYear;
  5         11  
  5         42  
8 5     5   2623 use Rose::HTML::Form::Field::Time::Split::HourMinuteSecond;
  5         19  
  5         67  
9              
10 5     5   44 use base 'Rose::HTML::Form::Field::DateTime::Split';
  5         12  
  5         966  
11              
12             our $VERSION = '0.550';
13              
14             sub build_field
15             {
16 18     18 1 72 my($self) = shift;
17              
18 18         112 $self->add_fields
19             (
20             date => 'datetime split mdy',
21             time => 'time split hms',
22             );
23             }
24              
25             sub decompose_value
26             {
27 163     163 1 337 my($self, $value) = @_;
28              
29 163 100       606 return undef unless(defined $value);
30              
31 11         49 my $date = $self->SUPER::inflate_value($value);
32              
33 11 100       44 unless($date)
34             {
35 5     5   39 no warnings;
  5         13  
  5         2179  
36             return
37             {
38 4   50     45 date => substr($value, 0, 10) || '',
      100        
39             time => substr($value, 10) || '',
40             }
41             }
42              
43 7         59 my($mdy, $time) = Rose::DateTime::Util::format_date($date, '%m/%d/%Y', '%I:%M:%S %p');
44              
45             return
46             {
47 7         1256 date => $mdy,
48             time => $time,
49             };
50             }
51              
52             sub coalesce_value
53             {
54 7     7 1 21 my($self) = shift;
55 14 50       61 return join(' ', map { defined($_) ? $_ : '' }
56 7         22 map { $self->field($_)->output_value } qw(date time));
  14         45  
57             }
58              
59             sub is_full
60             {
61 331     331 1 562 my($self) = shift;
62              
63 662 100       4437 my $count = grep { defined && length }
64 331         633 map { $self->field($_)->internal_value } qw(date time);
  662         2413  
65              
66 331 100       1166 return $count == 2 ? 1 : 0;
67             }
68              
69             sub deflate_value
70             {
71 2     2 1 6 my($self, $date) = @_;
72 2 100       22 return $self->input_value_filtered unless($date);
73 1         13 return Rose::DateTime::Util::format_date($date, '%m/%d/%Y %I:%M:%S %p');
74             }
75              
76             sub html_field
77             {
78 6     6 1 1458 my($self) = shift;
79              
80 6         27 return '<span class="datetime">' .
81             $self->field('date')->html_field . ' ' .
82             $self->field('time')->html_field .
83             '</span>';
84             }
85              
86             sub xhtml_field
87             {
88 2     2 1 7 my($self) = shift;
89              
90 2         7 return '<span class="datetime">' .
91             $self->field('date')->xhtml_field . ' ' .
92             $self->field('time')->xhtml_field .
93             '</span>';
94             }
95              
96             1;
97              
98             __END__
99              
100             =head1 NAME
101              
102             Rose::HTML::Form::Field::DateTime::Split::MDYHMS - Compound field for dates with separate text fields for month, day, year, hour, minute, and second, and a pop-up menu for AM/PM.
103              
104             =head1 SYNOPSIS
105              
106             $field =
107             Rose::HTML::Form::Field::DateTime::Split::MDYHMS->new(
108             label => 'When',
109             name => 'when',
110             default => '12/31/2002 6:30 p.m.');
111              
112             print $field->field('time.minute')->internal_value; # "30"
113             print $field->field('date.day')->internal_value; # "31"
114              
115             print $field->internal_value; # "2002-12-31T18:30:00"
116             print $field->output_value; # "12/31/2002 06:30:00 PM"
117              
118             $field->input_value('blah');
119              
120             # "Could not parse date: blah"
121             $field->validate or warn $field->error;
122              
123             $field->input_value('4/30/1980 1:23pm');
124              
125             $dt = $field->internal_value; # DateTime object
126              
127             print $dt->hour; # 13
128             print $dt->day_name; # Wednesday
129              
130             print $field->html;
131             ...
132              
133             =head1 DESCRIPTION
134              
135             L<Rose::HTML::Form::Field::DateTime::Split::MDYHMS> is a compound field for dates with separate text fields for month, day, year, hour, minute, and second, and a pop-up menu for AM/PM.
136              
137             This class inherits (indirectly) from both L<Rose::HTML::Form::Field::DateTime> and L<Rose::HTML::Form::Field::Compound>. This doesn't quite work out as expected without a bit of tweaking. We'd like L<inflate_value()|Rose::HTML::Form::Field/inflate_value> and L<validate()|Rose::HTML::Form::Field/validate> methods to be inherited from L<Rose::HTML::Form::Field::DateTime>, but everything else to be inherited from L<Rose::HTML::Form::Field::Compound>.
138              
139             To solve this problem, there's an intermediate class that imports the correct set of methods. This class then inherits from the intermediate class. This works, and isolates the tricky bits to a single intermediate class, but it also demonstrates the problems that can crop up when multiple inheritance is combined with a strong aversion to code duplication.
140              
141             Inheritance shenanigans aside, this class is a good example of a compound field that includes other compound fields and also provides an "inflated" internal value (a L<DateTime> object). This is the most complex custom field example in this distribution. It does everything: nested compound fields, validation, inflate/deflate, and coalesce/decompose.
142              
143             The date portion of the field is handled by a L<Rose::HTML::Form::Field::DateTime::Split::MonthDayYear> field, and the time portion is handled by a L<Rose::HTML::Form::Field::Time::Split::HourMinuteSecond> field.
144              
145             It is important that this class (indirectly) inherits from L<Rose::HTML::Form::Field::Compound>. See the L<Rose::HTML::Form::Field::Compound> documentation for more information.
146              
147             =head1 OBJECT METHODS
148              
149             =over 4
150              
151             =item B<date_parser [PARSER]>
152              
153             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.
154              
155             If the parser object has an C<error()> method, it will be called to set the error message after a failed parsing attempt.
156              
157             The parser object defaults to L<Rose::DateTime::Parser-E<gt>new()|Rose::DateTime::Parser/new>.
158              
159             =item B<time_zone [TZ]>
160              
161             If the parser object has a L<time_zone()|/time_zone> method, this method simply calls it, passing all arguments. Otherwise, undef is returned.
162              
163             =back
164              
165             =head1 SEE ALSO
166              
167             Other examples of custom fields:
168              
169             =over 4
170              
171             =item L<Rose::HTML::Form::Field::Email>
172              
173             A text field that only accepts valid email addresses.
174              
175             =item L<Rose::HTML::Form::Field::Time>
176              
177             Uses inflate/deflate to coerce input into a fixed format.
178              
179             =item L<Rose::HTML::Form::Field::DateTime>
180              
181             Uses inflate/deflate to convert input to a L<DateTime> object.
182              
183             =item L<Rose::HTML::Form::Field::DateTime::Range>
184              
185             A compound field whose internal value consists of more than one object.
186              
187             =item L<Rose::HTML::Form::Field::PhoneNumber::US::Split>
188              
189             A simple compound field that coalesces multiple subfields into a single value.
190              
191             =item L<Rose::HTML::Form::Field::DateTime::Split::MonthDayYear>
192              
193             A compound field that uses inflate/deflate convert input from multiple subfields into a L<DateTime> object.
194              
195             =back
196              
197             =head1 AUTHOR
198              
199             John C. Siracusa (siracusa@gmail.com)
200              
201             =head1 LICENSE
202              
203             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.