File Coverage

lib/Workflow/Action/InputField.pm
Criterion Covered Total %
statement 68 70 97.1
branch 26 28 92.8
condition 7 8 87.5
subroutine 12 12 100.0
pod 6 6 100.0
total 119 124 95.9


line stmt bran cond sub pod time code
1              
2             use warnings;
3 21     21   609 use strict;
  21         47  
  21         713  
4 21     21   138 use base qw( Class::Accessor );
  21         34  
  21         537  
5 21     21   99 use Log::Log4perl qw( get_logger );
  21         39  
  21         2485  
6 21     21   1933 use Workflow::Exception qw( configuration_error );
  21         82  
  21         123  
7 21     21   2450 use English qw( -no_match_vars );
  21         40  
  21         1404  
8 21     21   2697  
  21         7609  
  21         174  
9             $Workflow::Action::InputField::VERSION = '1.60';
10              
11             my @PROPS = qw( name label description type requirement
12             source_class source_list class );
13             __PACKAGE__->mk_accessors(@PROPS);
14              
15             my %INCLUDED = ();
16              
17             my ( $class, $params ) = @_;
18             my $log = get_logger($class);
19 75     75 1 1786 $log->debug("Instantiating new field '$params->{name}'")
20 75         203 if $params->{name};
21              
22 75 100       5741 my $self = bless {}, $class;
23              
24 75         20939 # Set all our parameters
25             foreach my $prop (@PROPS) {
26             next unless ( $params->{$prop} );
27 75         156 $self->$prop( $params->{$prop} );
28 600 100       2972 }
29 236         620  
30             # ...ensure our name is defined
31             unless ( $self->name ) {
32             my $id_string = '['
33 75 100       210 . join(
34             '] [', map {"$_: $params->{$_}"}
35             sort keys %{$params}
36 0         0 ) . ']';
37 1         14 configuration_error "Field found without name: $id_string";
  1         3  
38             }
39 1         4  
40             my $name = $self->name;
41             unless ( $self->label ) {
42 74         800 $self->label($name);
43 74 100       587 }
44 9         77 my $requirement = ( defined $params->{is_required}
45             && $params->{is_required} eq 'yes' ) ? 'required' : 'optional';
46             $self->requirement($requirement);
47 74 100 100     831  
48 74         186 # ...ensure a class associated with the input source exists
49             if ( my $source_class = $self->source_class ) {
50             $log->debug("Possible values for '$name' from '$source_class'");
51 74 100       707 unless ( $INCLUDED{$source_class} ) {
    100          
52 13         159 eval "require $source_class";
53 13 100       3725 if ($EVAL_ERROR) {
54 6         541 configuration_error "Failed to include source class ",
55 6 50       1004 "'$source_class' used in field '$name'";
56 0         0 }
57             $INCLUDED{$source_class}++;
58             }
59 6         34 $params->{values} = [ $source_class->get_possible_values($self) ];
60             } elsif ( $self->source_list ) {
61 13         81 $log->debug("Possible values for '$name' specified in config");
62             $params->{values} = [ split /\s*,\s*/, $self->source_list ];
63 13         257 }
64 13         3660  
65             my $values = $params->{values} || $params->{possible_values};
66             if ($values) {
67 74   66     1619 my @add_values = ( ref $values eq 'ARRAY' ) ? @{$values} : ($values);
68 74 100       151 $log->debug( "Values to use as source for field '$name': ",
69 26 50       91 join ', ', @add_values );
  26         72  
70 26         273 $self->add_possible_values(@add_values);
71             }
72 26         7524  
73             # Assign the default field type, subclasses may override...
74             $self->type('basic');
75              
76 74         181 $self->init($params);
77             return $self;
78 74         787 }
79 74         283  
80              
81             my ($self) = @_;
82 74     74 1 85 return ( $self->requirement eq 'required' ) ? 'yes' : 'no';
83             }
84              
85 3     3 1 5 my ($self) = @_;
86 3 100       6 return ( $self->requirement eq 'optional' ) ? 'yes' : 'no';
87             }
88              
89             my ($self) = @_;
90 3     3 1 5 $self->{_enumerated} ||= [];
91 3 100       7 return @{ $self->{_enumerated} };
92             }
93              
94             my ( $self, @values ) = @_;
95 2     2 1 4 foreach my $value (@values) {
96 2   100     7 my $this_value
97 2         3 = ( ref $value eq 'HASH' )
  2         6  
98             ? $value
99             : { label => $value, value => $value };
100             push @{ $self->{_enumerated} }, $this_value;
101 27     27 1 700 }
102 27         59 return @{ $self->{_enumerated} };
103 132 100       271 }
104              
105             1;
106              
107 132         125  
  132         233  
108             =pod
109 27         41  
  27         74  
110             =head1 NAME
111              
112             Workflow::Action::InputField - Metadata about information required by an Action
113              
114             =head1 VERSION
115              
116             This documentation describes version 1.60 of this package
117              
118             =head1 SYNOPSIS
119              
120             # Declare the fields needed by your action in the configuration...
121              
122             <action name="CreateUser">
123             <field name="username"
124             is_required="yes"
125             source_class="App::Field::ValidUsers" />
126             <field name="email"
127             is_required="yes" />
128             <field name="office"
129             source_list="Pittsburgh,Hong Kong,Moscow,Portland" />
130             ...
131              
132             =head1 DESCRIPTION
133              
134             A workflow Action can declare one or more input fields required to do
135             its job. Think of it as a way for the external world (your
136             application) to discover what information an action needs from it. The
137             application can request these fields from the workflow by action name
138             and present them to the user in whatever form appropriate for the
139             application. The sample command-line application shipped with this
140             distribution just cycles through them one at a time and presents a
141             query to the user for data entry.
142              
143             For instance, in the above declaration there are three fields,
144             'username', 'email' and 'office'. So your application might do:
145              
146             my @action_fields = $wf->get_action_fields( 'CreateUser' );
147             foreach my $field ( @action_fields ) {
148             print "Field ", $field->name, "\n",
149             $field->description, "\n",
150             "Required? ", $field->is_required, "\n";
151             my @enum = $field->get_possible_values;
152             if ( scalar @enum ) {
153             print "Possible values: \n";
154             foreach my $val ( @enum ) {
155             print " $val->{label} ($val->{value})\n";
156             }
157             }
158             print "Input? ";
159             my $response = <STDIN>;
160             chomp $response;
161             $wf->context->param( $field->name => $response );
162             }
163             $wf->execute_action( 'CreateUser' );
164              
165             =head1 METHODS
166              
167             =head2 Public Methods
168              
169             =head3 new( \%params )
170              
171             Typical constructor; will throw exception if 'name' is not defined or
172             if the property 'source_class' is defined but the class it specifies
173             is not available.
174              
175             You will usually not need to use or override this method unless you
176             derive your own input field class (see I<class> in L</"Properties">
177             below). For example, suppose you need to add extra properties to all
178             your fields like "index", "disabled", etc.
179              
180             In your actions definition XML file, you can just add them and the
181             parser will pick them up. Pay close attention the custom InputField
182             "class" property.
183              
184             <actions>
185             <type>foo</type>
186             <action name="Bar"
187             class="your::action::class">
188             <field index="0" name="id" type="integer" disabled="yes"
189             is_required="yes" class="your::custom::inputfieldclass"/>
190             </action>
191              
192             But you need to give them life by creating the accessors for these
193             extra properties. Just derive your custom fields class like so:
194              
195             package your::custom::inputfieldclass;
196              
197             use warnings;
198             use strict;
199              
200             use base qw( Workflow::Action::InputField );
201             use Workflow::Exception qw( workflow_error );
202              
203             # extra action class properties
204             my @EXTRA_PROPS = qw( index disabled );
205             __PACKAGE__->mk_accessors(@EXTRA_PROPS);
206              
207             sub new {
208             my ( $class, $params ) = @_;
209             my $self = $class->SUPER::new($params);
210             # set only our extra properties
211             foreach my $prop (@EXTRA_PROPS) {
212             next if ( $self->$prop );
213             $self->$prop( $params->{$prop} );
214             }
215             warn "INDEX IS NOW WORKING:".$self->index;
216             warn "AND SO IS DISABLED:".$self->disabled;
217             return $self;
218             }
219              
220             1;
221              
222              
223             =head3 is_required()
224              
225             Returns 'yes' if field is required, 'no' if optional.
226              
227             =head3 is_optional()
228              
229             Returns 'yes' if field is optional, 'no' if required.
230              
231             =head3 get_possible_values()
232              
233             Returns list of possible values for this field. Each possible value is
234             represented by a hashref with the keys 'label' and 'value' which makes
235             it easy to create dropdown lists in templates and the like.
236              
237             =head3 add_possible_values( @values )
238              
239             Adds possible values to be used for this field. Each item in
240             C<@values> may be a simple scalar or a hashref with the keys 'label'
241             and 'value'.
242              
243             =head3 init
244              
245             Init is a I<dummy> and just returns no special actions are taken
246              
247             =head2 Properties
248              
249             B<name> (required)
250              
251             Name of the field. This is what the action expects as the key in the
252             workflow context.
253              
254             B<label> (optional)
255              
256             Label of the field. If not set the value for C<name> is used.
257              
258             B<description> (optional)
259              
260             What does the field mean? This is not required for operation but it is
261             B<strongly> encouraged so your clients can create front ends to feed
262             you the information without much fuss.
263              
264             B<type> (optional)
265              
266             Field types are implementation dependant are they should be
267             intrinsically implemented by validators. In other words, you can use
268             any mnemonic value for your convinience like "integer", "text",
269             etc. but it won't affect anything unless you use a validator to
270             validate your action data. By default it is set to 'basic'.
271              
272             B<requirement> ('required'|'optional')
273              
274             If field is required, 'required', otherwise 'optional'.
275              
276             B<source_class> (optional)
277              
278             If set the field will call 'get_possible_values()' on the class when
279             the field is instantiated. This should return a list of either simple
280             scalars or a list of hashrefs with 'label' and 'value' keys.
281              
282             B<source_list> (optional)
283              
284             If set the field will use the specified comma-separated values as the
285             possible values for the field. The resulting list returned from
286             C<get_possible_values()> will have the same value for both the 'label'
287             and 'value' keys.
288              
289             B<class> (optional)
290              
291             You may specify a custom InputField class. It should C<use base qw(
292             Workflow::Action );> and probably override the new() method which
293             should call SUPER::new($params). See L</"new( \%params )"> above for an
294             example.
295              
296             =head1 SEE ALSO
297              
298             =over
299              
300             =item * L<Workflow::Action>
301              
302             =back
303              
304             =head1 COPYRIGHT
305              
306             Copyright (c) 2003-2022 Chris Winters. All rights reserved.
307              
308             This library is free software; you can redistribute it and/or modify
309             it under the same terms as Perl itself.
310              
311             Please see the F<LICENSE>
312              
313             =head1 AUTHORS
314              
315             Please see L<Workflow>
316              
317             =cut