Perl Workflow module with validator

ε祈祈猫儿з 提交于 2019-12-07 04:46:51

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!