File Coverage

blib/lib/Workflow/Validator.pm
Criterion Covered Total %
statement 16 16 100.0
branch 3 4 75.0
condition n/a
subroutine 5 5 100.0
pod 1 1 100.0
total 25 26 96.1


line stmt bran cond sub pod time code
1             package Workflow::Validator;
2              
3 36     36   1282739 use warnings;
  36         80  
  36         2363  
4 36     36   209 use strict;
  36         110  
  36         868  
5 36     36   385 use v5.14.0;
  36         156  
6 36     36   198 use parent qw( Workflow::Base );
  36         79  
  36         273  
7              
8             $Workflow::Validator::VERSION = '2.09';
9              
10             my @FIELDS = qw( description name );
11             __PACKAGE__->mk_accessors(@FIELDS);
12              
13             sub init {
14 64     64 1 181 my ( $self, $params ) = @_;
15              
16 64         496 $self->description( $params->{description} );
17 64 100       1585 if ( $params->{name} ) {
18 58         370 $self->name( $params->{name} );
19             } else {
20 6 50       33 $self->name((ref $self ? ref $self : $self) . " (init in Action)");
21             }
22             }
23              
24             1;
25              
26             __END__
27              
28             =pod
29              
30             =head1 NAME
31              
32             Workflow::Validator - Interface definition for data validation
33              
34             =head1 VERSION
35              
36             This documentation describes version 2.09 of this package
37              
38             =head1 SYNOPSIS
39              
40             # First declare the validator...
41             validator:
42             - name: DateValidator
43             class: MyApp::Validator::Date
44             param:
45             - name: date_format
46             value: '%Y-%m-%d %H:%M'
47              
48             # Then associate the validator with runtime data from the context...
49             action:
50             - name: MyAction
51             validator:
52             - name: DateValidator
53             arg:
54             - '$due_date'
55              
56             # TODO: You can also inintialize and instantiate in one step if you
57             # don't need to centralize or reuse (does this work?)
58              
59             action:
60             - name: MyAction
61             validator:
62             - class: MyApp::Validator::Date
63             param:
64             - name: date_format
65             value: '%Y-%m-%d %H:%M'
66             arg:
67             - '$due_date'
68              
69             # Then implement the logic using your favorite object system; e.g. Moo
70              
71             package MyApp::Validator::Date;
72              
73             use strict;
74             use DateTime::Format::Strptime;
75             use Workflow::Exception qw( validation_error );
76              
77             use Moo;
78              
79             has description => (is => 'ro', required => 0);
80              
81             has name => (is => 'ro', required => 1);
82              
83             has date_format => (is => 'ro', required => 1);
84              
85             has formatter => (is => 'ro', builder => '_build_formatter');
86              
87             around BUILDARGS => sub {
88             my ( $orig, $class, @args ) = @_;
89              
90             # Note: When you derive from Workflow::Base, this mapping is done for you
91             @args = (%{$args[0]},
92             map {
93             $_ => $args[0]->{param}->{$_}
94             } keys %{$args[0]->{param} // {}}
95             )
96             if scalar(@args) == 1 and ref $args[0] eq 'HASH';
97             return $class->$orig(@args);
98             }
99              
100             sub _build_formatter {
101             my ( $self ) = @_;
102              
103             return DateTime::Format::Strptime->new(
104             pattern => $self->date_format,
105             on_error => 'undef'
106             );
107             }
108              
109             sub validate {
110             my ( $self, $wf, $date_string ) = @_;
111             my $fmt = $self->formatter;
112             my $date_object = $fmt->parse_datetime( $date_string );
113             unless ( $date_object ) {
114             validation_error
115             "Date '$date_string' does not match pattern '", $fmt->pattern, "' ",
116             "due to error '", $fmt->errstr, "'";
117             }
118             }
119              
120              
121             # Or, implement the same, based on Workflow::Base
122              
123             package MyApp::Validator::Date::Alternative;
124              
125             use warnings;
126             use strict;
127             use base qw( Workflow::Base );
128              
129             use DateTime::Format::Strptime;
130             use Workflow::Exception qw( configuration_error validation_error );
131              
132             my @FIELDS = qw( name date_format formatter );
133             __PACKAGE__->mk_accessors(@FIELDS);
134              
135             sub init {
136             my ( $self, $params ) = @_;
137              
138             $self->name( $params->{name} );
139             $self->date_format( $params->{date_format});
140             $self->formatter( DateTime::Format::Strptime->new(
141             pattern => $self->date_format,
142             on_error => 'undef'));
143             }
144              
145              
146             sub validate {
147             my ( $self, $wf, $date_string ) = @_;
148             my $fmt = $self->formatter;
149             my $date_object = $fmt->parse_datetime( $date_string );
150             unless ( $date_object ) {
151             validation_error
152             "Date '$date_string' does not match pattern '", $fmt->pattern, "' ",
153             "due to error '", $fmt->errstr, "'";
154             }
155             }
156              
157             1;
158              
159              
160              
161             =head1 DESCRIPTION
162              
163             Validators specified by 'validator_name' are looked up in the
164             L<Workflow::Factory> which reads a separate configuration and
165             generates validators. (Generally all validators should be declared,
166             but it is not required.)
167              
168             Validators are objects with a single public method, 'validate()' that
169             take as arguments a workflow object and a list of parameters. The
170             parameters are filled in by the workflow engine in the order of
171             declaration in the Action.
172              
173             The idea behind a validator is that it validates data but does not
174             care where it comes from.
175              
176             =head1 SUBCLASSING
177              
178             The validator is an interface definition, meaning that the validator
179             does not want or need to be subclassed. Any class can act as a
180             validator, as long as it adheres to the interface definition below.
181              
182              
183             =head1 INTERFACE
184              
185             =head2 validate( $workflow, $data )
186              
187             Throws a L<Workflow::ValidationError> when C<$workflow> doesn't comply
188             with the requirements of the validator. Returns successfully when it
189             does. In order to assess the state of the workflow, the validator can
190             directly use the workflow context as well as the mapped data.
191              
192             When an action definition maps data into the validator, the validator may
193             or may not choose to use it to determine the validity of the workflow state.
194              
195             Please note that the workflow engine currently has no means to detect the
196             number of data elements expected to be mapped into the validator; failure
197             to map the correct number in the configuration, should be detected at run
198             time (and can't be prevented with a configuration error).
199              
200             =head1 COPYRIGHT
201              
202             Copyright (c) 2003-2021 Chris Winters. All rights reserved.
203              
204             This library is free software; you can redistribute it and/or modify
205             it under the same terms as Perl itself.
206              
207             Please see the F<LICENSE>
208              
209             =head1 AUTHORS
210              
211             Please see L<Workflow>
212              
213             =cut