问题
i'm trying to get things work with perl Workflow module - http://search.cpan.org/~jonasbn/Workflow/
I managed to figure out how it works with workflows, actions, conditions and all but i can't get it to apply validator class to the action.
My _init method from validator loads and prints out the line that i put there for testing but validate method is not triggered ever. Also, when dumping $self->get_validators() from action class i get empty list.
I created a short example so please try it and help out if you see the problem. Tnx!
link to code - https://github.com/vmcooper/perl_workflow_test
Running the program
Program starts with
Answer: London
If you answer right the action should change state to 'finished'. Try answering wrong first.
Capital city of England:
if you answer "Birmingham" it should write
Your answer is being validated!
and ask the question again.
When you answer "London" it should
Correct! Current state of workflow is - finished
edit Now it writes out "Correct! Current state of workflow is - finished" whatever your answer is.
workflow_test.pl
use strict;
use Log::Log4perl qw( get_logger );
use Workflow::Factory qw( FACTORY );
Log::Log4perl::init( 'log4perl.conf' );
system('clear');
# Stock the factory with the configurations; we can add more later if we want
FACTORY->add_config_from_file(
workflow => 'workflow.xml',
action => 'action.xml',
persister => 'persister.xml',
validator => 'validator.xml'
);
my $workflow = FACTORY->create_workflow( "Workflow1" );
my $context = $workflow->context;
while ( $workflow->state eq "INITIAL" ) {
print "If you answer right the action should change state to 'finished'. Try answering wrong first.\n";
my $city = get_response( "Capital city of England: " );
print "You answered - $city\n";
$workflow->execute_action( 'action1' );
if( $workflow->state eq "INITIAL" ) {
print "Your answer is wrong! try again!\n\n";
}
}
print "\nCorrect! Current state of workflow is - ".$workflow->state."\n\n";
# Generic routine to read a response from the command-line (defaults,
# etc.) Note that return value has whitespace at the end/beginning of
# the routine trimmed.
sub get_response {
my ( $msg ) = @_;
print $msg;
my $response = <STDIN>;
chomp $response;
$response =~ s/^\s+//;
$response =~ s/\s+$//;
return $response;
}
workflow.xml
<workflow>
<type>Workflow1</type>
<time_zone>local</time_zone>
<description>This is my workflow.</description>
<persister>Persister1</persister>
<state name="INITIAL">
<action name="action1" resulting_state="finished"/>
</state>
<state name="finished" />
</workflow>
action.xml
<actions>
<action name="action1" class="App::Action::Action1" >
<validator name="validator1">
<arg>$city</arg>
</validator>
</action>
</actions>
validator.xml
<validators>
<validator name="validator1" class="App::Validator::Validator1">
<param name="answer" value="London" />
</validator>
</validators>
App::Action::Action1.pm
package App::Action::Action1;
use strict;
use base qw( Workflow::Action );
use Workflow::Exception qw( validation_error configuration_error );
use Data::Dumper;
sub new {
my $class = shift;
my $self = {};
bless ($self, $class);
return $self;
}
sub execute {
my $self = shift;
my $wf = shift;
print "App::Action::Action1::Execute\n";
print "Validators: ".Dumper($self->get_validators())."\n";
}
1;
App::Validator::Validator1.pm
package App::Validator::Validator1;
use strict;
use base qw( Workflow::Validator );
use Workflow::Exception qw( validation_error configuration_error );
use Data::Dumper;
use Carp qw(carp);
sub _init {
my ( $self, $params ) = @_;
unless ( $params->{answer} ) {
configuration_error
"You must define a value for 'answer' in ",
"declaration of validator ", $self->name;
}
if ( ref $params->{answer} ) {
configuration_error
"The value for 'answer' must be a simple scalar in ",
"declaration of validator ", $self->name;
}
print "Answer: ".$params->{answer}."\n";
$self->{ answer => $params->{answer} };
}
sub validate {
my ( $self, $wf, $city ) = @_;
print "Your answer is being validated!\n";
print "Your answer is - ".$city."\n";
my $check;
if ( $city eq $self->{answer} ){
$check = 1;
} else {
$check = 0;
}
unless ( $check ) {
validation_error "Validation error!";
}
}
1;
Edit: If i dump workflow object right after creation and before any action is executed i get this:
Workflow: $VAR1 = bless( {
'_states' => {
'INITIAL' => bless( {
...,
'_actions' => {
'action1' => {
'resulting_state' => 'finished',
'name' => 'action1'
}
},
'_factory' => bless( {
...,
'_action_config' => {
'default' => {
'action1' => {
'name' => 'action1',
'class' => 'App::Action::Action1',
'validator' => [
{
'arg' => [
'$city'
],
'name' => 'validator1'
}
]
}
}
},
'_validators' => {
'validator1' => bless( {
'name' => 'validator1',
'class' => 'App::Validator::Validator1',
'PARAMS' => {}
}, 'App::Validator::Validator1' )
},
'_validator_config' => {
'validator1' => {
'answer' => 'London',
'name' => 'validator1',
'class' => 'App::Validator::Validator1'
}
},
...
}, 'Workflow::Factory' ),
'type' => 'Workflow1',
'PARAMS' => {}
}, 'Workflow::State' ),
'finished' => $VAR1->{'_states'}{'INITIAL'}{'_factory'}{'_workflow_state'}{'Workflow1'}[1]
},
...
}, 'Workflow' );
As you can see, validator is here and everything is set up and looks like it's ok but the validator is not applied.
回答1:
Looks like we will have to wait for this a bit or we can participate in a project to get this functionaity done.
Scroll to the "get_validators" heading and you will se a "#TODO" mark. I'm not sure whether this means the documentation needs to be done or code but i did look at the code a bit and it looks like the code needs to be done for this functionality. http://search.cpan.org/~jonasbn/Workflow-1.41/lib/Workflow/Factory.pm
Correct me if i'm wrong.
回答2:
I located several issues in your example.
Action1.pm has a constructor, this interferes with the inheritance, So this should be deleted leaving your action class as follows
package App::Action::Action1;
use strict;
use base qw( Workflow::Action );
use Workflow::Exception qw( validation_error configuration_error );
use Data::Dumper;
sub execute {
my $self = shift;
my $wf = shift;
print "App::Action::Action1::Execute\n";
print "Validators: ".Dumper($self->get_validators())."\n";
}
1;
The main issue that your application receives the input from the user, but you never feed it to the workflow. This has be done using context, like so:
$context->param( answer => $city );
The validator should looks as follows:
package App::Validator::Validator1;
use strict;
use base qw( Workflow::Validator );
use Workflow::Exception qw( validation_error configuration_error );
use Data::Dumper;
use Carp qw(carp);
sub _init {
my ( $self, $params ) = @_;
unless ( $params->{answer} ) {
configuration_error
"You must define a value for 'answer' in ",
"declaration of validator ", $self->name;
}
if ( ref $params->{answer} ) {
configuration_error
"The value for 'answer' must be a simple scalar in ",
"declaration of validator ", $self->name;
}
print "Answer: ".$params->{answer}."\n";
$self->{answer} = $params->{answer};
}
sub validate {
my ( $self, $wf ) = @_;
my $city = $wf->context->param('answer');
print "Your answer is being validated!\n";
print "Your answer is - ".$city."\n";
my $check;
if ( $city eq $self->{answer} ){
$check = 1;
} else {
$check = 0;
}
unless ( $check ) {
validation_error "Validation error!";
}
}
1;
And your main application should resemble the following:
use strict;
use Log::Log4perl qw( get_logger );
use Workflow::Factory qw( FACTORY );
use lib qw(lib);
Log::Log4perl::init( 'log4perl.conf' );
system('clear');
# Stock the factory with the configurations; we can add more later if we want
FACTORY->add_config_from_file(
workflow => 'workflow.xml',
action => 'action.xml',
persister => 'persister.xml',
validator => 'validator.xml'
);
my $workflow = FACTORY->create_workflow( "Workflow1" );
my $context = $workflow->context;
while ( $workflow->state eq "INITIAL" ) {
print "If you answer right the action should change state to 'finished'. Try answering wrong first.\n";
my $city = get_response( "Capital city of England: " );
print "You answered - $city\n";
$context->param( answer => $city );
$workflow->execute_action( 'action1' );
if( $workflow->state eq "INITIAL" ) {
print "Your answer is wrong! try again!\n\n";
}
}
print "\nCorrect! Current state of workflow is - ".$workflow->state."\n\n";
# Generic routine to read a response from the command-line (defaults,
# etc.) Note that return value has whitespace at the end/beginning of
# the routine trimmed.
sub get_response {
my ( $msg ) = @_;
print $msg;
my $response = <STDIN>;
chomp $response;
$response =~ s/^\s+//;
$response =~ s/\s+$//;
return $response;
}
I understand your confusion, since the documentation does not properly reflect this fact and it cannot be read from the example application in the distribution. I will update the documentation accordingly.
来源:https://stackoverflow.com/questions/27921691/perl-workflow-module-with-validator