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              
2             use strict;
3 5     5   4549  
  5         9  
  5         126  
4             use Rose::DateTime::Util();
5 5     5   28  
  5         13  
  5         78  
6             use Rose::HTML::Form::Field::DateTime::Split::MonthDayYear;
7 5     5   516 use Rose::HTML::Form::Field::Time::Split::HourMinuteSecond;
  5         10  
  5         32  
8 5     5   2001  
  5         15  
  5         55  
9             use base 'Rose::HTML::Form::Field::DateTime::Split';
10 5     5   28  
  5         9  
  5         760  
11             our $VERSION = '0.550';
12              
13             {
14             my($self) = shift;
15              
16 18     18 1 48 $self->add_fields
17             (
18 18         89 date => 'datetime split mdy',
19             time => 'time split hms',
20             );
21             }
22              
23             {
24             my($self, $value) = @_;
25              
26             return undef unless(defined $value);
27 163     163 1 368  
28             my $date = $self->SUPER::inflate_value($value);
29 163 100       646  
30             unless($date)
31 11         42 {
32             no warnings;
33 11 100       30 return
34             {
35 5     5   32 date => substr($value, 0, 10) || '',
  5         10  
  5         1797  
36             time => substr($value, 10) || '',
37             }
38 4   50     33 }
      100        
39              
40             my($mdy, $time) = Rose::DateTime::Util::format_date($date, '%m/%d/%Y', '%I:%M:%S %p');
41              
42             return
43 7         48 {
44             date => $mdy,
45             time => $time,
46             };
47 7         1096 }
48              
49             {
50             my($self) = shift;
51             return join(' ', map { defined($_) ? $_ : '' }
52             map { $self->field($_)->output_value } qw(date time));
53             }
54 7     7 1 15  
55 14 50       46 {
56 7         17 my($self) = shift;
  14         39  
57              
58             my $count = grep { defined && length }
59             map { $self->field($_)->internal_value } qw(date time);
60              
61 331     331 1 478 return $count == 2 ? 1 : 0;
62             }
63 662 100       3772  
64 331         503 {
  662         1982  
65             my($self, $date) = @_;
66 331 100       893 return $self->input_value_filtered unless($date);
67             return Rose::DateTime::Util::format_date($date, '%m/%d/%Y %I:%M:%S %p');
68             }
69              
70             {
71 2     2 1 5 my($self) = shift;
72 2 100       8  
73 1         9 return '<span class="datetime">' .
74             $self->field('date')->html_field . ' ' .
75             $self->field('time')->html_field .
76             '</span>';
77             }
78 6     6 1 1080  
79             {
80 6         19 my($self) = shift;
81              
82             return '<span class="datetime">' .
83             $self->field('date')->xhtml_field . ' ' .
84             $self->field('time')->xhtml_field .
85             '</span>';
86             }
87              
88 2     2 1 6 1;
89              
90 2         7  
91             =head1 NAME
92              
93             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.
94              
95             =head1 SYNOPSIS
96              
97             $field =
98             Rose::HTML::Form::Field::DateTime::Split::MDYHMS->new(
99             label => 'When',
100             name => 'when',
101             default => '12/31/2002 6:30 p.m.');
102              
103             print $field->field('time.minute')->internal_value; # "30"
104             print $field->field('date.day')->internal_value; # "31"
105              
106             print $field->internal_value; # "2002-12-31T18:30:00"
107             print $field->output_value; # "12/31/2002 06:30:00 PM"
108              
109             $field->input_value('blah');
110              
111             # "Could not parse date: blah"
112             $field->validate or warn $field->error;
113              
114             $field->input_value('4/30/1980 1:23pm');
115              
116             $dt = $field->internal_value; # DateTime object
117              
118             print $dt->hour; # 13
119             print $dt->day_name; # Wednesday
120              
121             print $field->html;
122             ...
123              
124             =head1 DESCRIPTION
125              
126             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.
127              
128             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>.
129              
130             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.
131              
132             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.
133              
134             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.
135              
136             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.
137              
138             =head1 OBJECT METHODS
139              
140             =over 4
141              
142             =item B<date_parser [PARSER]>
143              
144             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.
145              
146             If the parser object has an C<error()> method, it will be called to set the error message after a failed parsing attempt.
147              
148             The parser object defaults to L<Rose::DateTime::Parser-E<gt>new()|Rose::DateTime::Parser/new>.
149              
150             =item B<time_zone [TZ]>
151              
152             If the parser object has a L<time_zone()|/time_zone> method, this method simply calls it, passing all arguments. Otherwise, undef is returned.
153              
154             =back
155              
156             =head1 SEE ALSO
157              
158             Other examples of custom fields:
159              
160             =over 4
161              
162             =item L<Rose::HTML::Form::Field::Email>
163              
164             A text field that only accepts valid email addresses.
165              
166             =item L<Rose::HTML::Form::Field::Time>
167              
168             Uses inflate/deflate to coerce input into a fixed format.
169              
170             =item L<Rose::HTML::Form::Field::DateTime>
171              
172             Uses inflate/deflate to convert input to a L<DateTime> object.
173              
174             =item L<Rose::HTML::Form::Field::DateTime::Range>
175              
176             A compound field whose internal value consists of more than one object.
177              
178             =item L<Rose::HTML::Form::Field::PhoneNumber::US::Split>
179              
180             A simple compound field that coalesces multiple subfields into a single value.
181              
182             =item L<Rose::HTML::Form::Field::DateTime::Split::MonthDayYear>
183              
184             A compound field that uses inflate/deflate convert input from multiple subfields into a L<DateTime> object.
185              
186             =back
187              
188             =head1 AUTHOR
189              
190             John C. Siracusa (siracusa@gmail.com)
191              
192             =head1 LICENSE
193              
194             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.