Ready for 7.10.29 development.
This commit is contained in:
commit
c806f99b7b
4236 changed files with 1217679 additions and 0 deletions
580
lib/WebGUI/Workflow.pm
Normal file
580
lib/WebGUI/Workflow.pm
Normal file
|
|
@ -0,0 +1,580 @@
|
|||
package WebGUI::Workflow;
|
||||
|
||||
|
||||
=head1 LEGAL
|
||||
|
||||
-------------------------------------------------------------------
|
||||
WebGUI is Copyright 2001-2009 Plain Black Corporation.
|
||||
-------------------------------------------------------------------
|
||||
Please read the legal notices (docs/legal.txt) and the license
|
||||
(docs/license.txt) that came with this distribution before using
|
||||
this software.
|
||||
-------------------------------------------------------------------
|
||||
http://www.plainblack.com info@plainblack.com
|
||||
-------------------------------------------------------------------
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use WebGUI::Workflow::Activity;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Package WebGUI::Workflow
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This package provides the API for manipulating workflows.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use WebGUI::Workflow;
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
These methods are available from this class:
|
||||
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 addActivity ( class [, id ] )
|
||||
|
||||
Adds an activity to this workflow. Returns a reference to the new activity object.
|
||||
|
||||
=head3 class
|
||||
|
||||
The classname of the activity to add.
|
||||
|
||||
=head3 id
|
||||
|
||||
Normally an ID will be generated for you, but if you want to override this and provide your own 22 character id, then you can specify it here.
|
||||
|
||||
=cut
|
||||
|
||||
sub addActivity {
|
||||
my $self = shift;
|
||||
my $class = shift;
|
||||
my $id = shift;
|
||||
return WebGUI::Workflow::Activity->create($self->session, $self->getId, $id, $class);
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 create ( session, properties, [, id ] )
|
||||
|
||||
Creates a new instance of a workflow.
|
||||
|
||||
=head3 session
|
||||
|
||||
A reference to the current session.
|
||||
|
||||
=head3 properties
|
||||
|
||||
A hash reference of properties to set for this workflow. See set() for details.
|
||||
|
||||
=head3 id
|
||||
|
||||
Normally an ID will be generated for you, but if you want to override this and provide your own 22 character id, then you can specify it here.
|
||||
|
||||
=cut
|
||||
|
||||
sub create {
|
||||
my $class = shift;
|
||||
my $session = shift;
|
||||
my $properties = shift;
|
||||
my $id = shift;
|
||||
my $workflowId = $session->db->setRow("Workflow","workflowId",{workflowId=>"new",enabled=>0},$id);
|
||||
my $self = $class->new($session, $workflowId);
|
||||
$self->set($properties);
|
||||
return $self;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 delete ( )
|
||||
|
||||
Removes this workflow and everything associated with it..
|
||||
|
||||
=cut
|
||||
|
||||
sub delete {
|
||||
my $self = shift;
|
||||
|
||||
foreach my $cron (@{$self->getCrons}) {
|
||||
$cron->delete;
|
||||
}
|
||||
|
||||
foreach my $instance (@{$self->getInstances}) {
|
||||
$instance->delete;
|
||||
}
|
||||
|
||||
foreach my $activity (@{$self->getActivities}) {
|
||||
$activity->delete;
|
||||
}
|
||||
|
||||
$self->session->db->deleteRow("Workflow","workflowId",$self->getId);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 deleteActivity ( activityId )
|
||||
|
||||
Removes an activity from this workflow. This is just a convenience method, so you don't have to manually load and construct activity objects when you're already working with a workflow.
|
||||
|
||||
=head3 activityId
|
||||
|
||||
The unique id of the activity to remove.
|
||||
|
||||
=cut
|
||||
|
||||
sub deleteActivity {
|
||||
my $self = shift;
|
||||
my $activityId = shift;
|
||||
my $activity = $self->getActivity($activityId);
|
||||
if ($activity) {
|
||||
$activity->delete;
|
||||
$self->reorderActivities;
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 demoteActivity ( activityId )
|
||||
|
||||
Moves an activity down one position in the execution order.
|
||||
|
||||
=head3 activityId
|
||||
|
||||
The id of the activity to move.
|
||||
|
||||
=cut
|
||||
|
||||
sub demoteActivity {
|
||||
my $self = shift;
|
||||
my $thisId = shift;
|
||||
my ($thisSeq) = $self->session->db->quickArray("select sequenceNumber from WorkflowActivity where activityId=?",[$thisId]);
|
||||
my ($otherId) = $self->session->db->quickArray("select activityId from WorkflowActivity where workflowId=? and sequenceNumber=?",[$self->getId, $thisSeq+1]);
|
||||
if ($otherId ne "") {
|
||||
$self->session->db->write("update WorkflowActivity set sequenceNumber=sequenceNumber+1 where activityId=?", [$thisId]);
|
||||
$self->session->db->write("update WorkflowActivity set sequenceNumber=sequenceNumber-1 where activityId=?", [$otherId]);
|
||||
$self->reorderActivities;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 DESTROY ( )
|
||||
|
||||
Deconstructor.
|
||||
|
||||
=cut
|
||||
|
||||
sub DESTROY {
|
||||
my $self = shift;
|
||||
undef $self;
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 get ( name )
|
||||
|
||||
Returns the value for a given property.
|
||||
|
||||
=cut
|
||||
|
||||
sub get {
|
||||
my $self = shift;
|
||||
my $name = shift;
|
||||
return $self->{_data}{$name};
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getActivity ( activityId )
|
||||
|
||||
Retrieves an activity object. This is just a convenience method, so you don't have to manually load and construct activity objects when you're already working with a workflow.
|
||||
|
||||
=head3 activityId
|
||||
|
||||
The unique id of the activity.
|
||||
|
||||
=cut
|
||||
|
||||
sub getActivity {
|
||||
my $self = shift;
|
||||
my $activityId = shift;
|
||||
my $activity = WebGUI::Workflow::Activity->new($self->session, $activityId);
|
||||
return $activity;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getActivities ( )
|
||||
|
||||
Returns an array reference of the activity objects associated with this workflow.
|
||||
|
||||
=cut
|
||||
|
||||
sub getActivities {
|
||||
my $self = shift;
|
||||
my @activities = ();
|
||||
my $rs = $self->session->db->prepare("select activityId from WorkflowActivity where workflowId=? order by sequenceNumber");
|
||||
$rs->execute([$self->getId]);
|
||||
while (my ($activityId) = $rs->array) {
|
||||
push(@activities, $self->getActivity($activityId));
|
||||
}
|
||||
return \@activities;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getInstances ( )
|
||||
|
||||
Returns an array reference of the instance objects currently existing for this workflow.
|
||||
|
||||
=cut
|
||||
|
||||
sub getInstances {
|
||||
my $self = shift;
|
||||
my @instances = ();
|
||||
my $rs = $self->session->db->read("SELECT instanceId FROM WorkflowInstance WHERE workflowId = ?", [$self->getId]);
|
||||
while (my ($instanceId) = $rs->array) {
|
||||
push(@instances, WebGUI::Workflow::Instance->new($self->session, $instanceId));
|
||||
}
|
||||
return \@instances;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getCrons ( )
|
||||
|
||||
Returns an array reference of the cron objects that trigger this workflow.
|
||||
|
||||
=cut
|
||||
|
||||
sub getCrons {
|
||||
my $self = shift;
|
||||
my @crons = ();
|
||||
my $rs = $self->session->db->read("SELECT taskId FROM WorkflowSchedule WHERE workflowId = ?", [$self->getId]);
|
||||
while (my ($taskId) = $rs->array) {
|
||||
push(@crons, WebGUI::Workflow::Cron->new($self->session, $taskId));
|
||||
}
|
||||
return \@crons;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getId ( )
|
||||
|
||||
Returns the ID of this workflow.
|
||||
|
||||
=cut
|
||||
|
||||
sub getId {
|
||||
my $self = shift;
|
||||
return $self->{_id};
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getList ( session, [ type ] )
|
||||
|
||||
Returns a hash reference of workflowId/title pairs of all enabled workflows. This is a class method.
|
||||
|
||||
=head3 session
|
||||
|
||||
A reference to the current session.
|
||||
|
||||
=head3 type
|
||||
|
||||
If specified this will limit the list to a certain type of workflow based upon the object type that the workflow is set up to handle.
|
||||
|
||||
=cut
|
||||
|
||||
sub getList {
|
||||
my $class = shift;
|
||||
my $session = shift;
|
||||
my $type = shift;
|
||||
my $sql = "select workflowId, title from Workflow where enabled=1";
|
||||
my @params;
|
||||
if ($type) {
|
||||
$sql .= " and type=?";
|
||||
push(@params, $type);
|
||||
}
|
||||
return $session->db->buildHashRef($sql, \@params);
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getNextActivity ( [ activityId ] )
|
||||
|
||||
Returns the next activity in the workflow after the activity specified.
|
||||
If no activity id is specified, then the first workflow will be returned.
|
||||
|
||||
=head3 activityId
|
||||
|
||||
The unique id of an activity in this workflow.
|
||||
|
||||
=cut
|
||||
|
||||
sub getNextActivity {
|
||||
my $self = shift;
|
||||
my $activityId = shift;
|
||||
my $id = $self->getNextActivityId($activityId);
|
||||
return $self->getActivity($id);
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 getNextActivityId ( [ activityId ] )
|
||||
|
||||
Returns the ID of the next activity in the workflow after the activity specified.
|
||||
If no activity id is specified, then the first workflow will be returned.
|
||||
|
||||
=head3 activityId
|
||||
|
||||
The unique id of an activity in this workflow.
|
||||
|
||||
=cut
|
||||
|
||||
sub getNextActivityId {
|
||||
my $self = shift;
|
||||
my $activityId = shift;
|
||||
my ($sequenceNumber) = $self->session->db->quickArray("select sequenceNumber from WorkflowActivity where activityId=?", [$activityId]);
|
||||
$sequenceNumber++;
|
||||
my ($id) = $self->session->db->quickArray("select activityId from WorkflowActivity where workflowId=?
|
||||
and sequenceNumber>=? order by sequenceNumber", [$self->getId, $sequenceNumber]);
|
||||
return $id;
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 hasNextActivity ( [ activityId ] )
|
||||
|
||||
Returns true if there is an activity after the specified activity.
|
||||
If no activity id is specified, then the first workflow will be returned.
|
||||
|
||||
=head3 activityId
|
||||
|
||||
The unique id of an activity in this workflow.
|
||||
|
||||
=cut
|
||||
|
||||
sub hasNextActivity {
|
||||
my $self = shift;
|
||||
return $self->getNextActivityId(@_) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 isParallel ( )
|
||||
|
||||
Returns 1 if the mode is set to "parallel".
|
||||
|
||||
=cut
|
||||
|
||||
sub isParallel {
|
||||
my $self = shift;
|
||||
return ($self->get("mode") eq "parallel") ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 isRealtime ( )
|
||||
|
||||
Depricated. Always returns 0.
|
||||
|
||||
=cut
|
||||
|
||||
sub isRealtime {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 isSerial ( )
|
||||
|
||||
Returns 1 if the mode is set to "serial".
|
||||
|
||||
=cut
|
||||
|
||||
sub isSerial {
|
||||
my $self = shift;
|
||||
return ($self->get("mode") eq "serial") ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 isSingleton ( )
|
||||
|
||||
Returns 1 if the mode is set to "singleton".
|
||||
|
||||
=cut
|
||||
|
||||
sub isSingleton {
|
||||
my $self = shift;
|
||||
return ($self->get("mode") eq "singleton") ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 new ( session, workflowId )
|
||||
|
||||
Constructor.
|
||||
|
||||
=head3 session
|
||||
|
||||
A reference to the current session.
|
||||
|
||||
=head3 workflowId
|
||||
|
||||
The unique id of this workflow.
|
||||
|
||||
=cut
|
||||
|
||||
sub new {
|
||||
my $class = shift;
|
||||
my $session = shift;
|
||||
my $workflowId = shift;
|
||||
my $data = $session->db->getRow("Workflow","workflowId", $workflowId);
|
||||
return undef unless $data->{workflowId};
|
||||
bless {_session=>$session, _id=>$workflowId, _data=>$data}, $class;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 promoteActivity ( activityId )
|
||||
|
||||
Moves an activity up one position in the execution order.
|
||||
|
||||
=head3 activityId
|
||||
|
||||
The id of the activity to move.
|
||||
|
||||
=cut
|
||||
|
||||
sub promoteActivity {
|
||||
my $self = shift;
|
||||
my $thisId = shift;
|
||||
my ($thisSeq) = $self->session->db->quickArray("select sequenceNumber from WorkflowActivity where activityId=?",[$thisId]);
|
||||
my ($otherId) = $self->session->db->quickArray("select activityId from WorkflowActivity where workflowId=? and sequenceNumber=?",[$self->getId, $thisSeq-1]);
|
||||
if ($otherId ne "") {
|
||||
$self->session->db->write("update WorkflowActivity set sequenceNumber=sequenceNumber-1 where activityId=?", [$thisId]);
|
||||
$self->session->db->write("update WorkflowActivity set sequenceNumber=sequenceNumber+1 where activityId=?", [$otherId]);
|
||||
$self->reorderActivities;
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head3 reorderActivities ( )
|
||||
|
||||
Reorders the acitivities to make sure they're consecutive.
|
||||
|
||||
=cut
|
||||
|
||||
sub reorderActivities {
|
||||
my $self = shift;
|
||||
my $sth = $self->session->db->read("select activityId from WorkflowActivity where workflowId=? order by sequenceNumber",[$self->getId]);
|
||||
my $i = 0;
|
||||
while (my ($id) = $sth->array) {
|
||||
$i++;
|
||||
$self->session->db->write("update WorkflowActivity set sequenceNumber=? where activityId=?",[$i, $id]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 session ( )
|
||||
|
||||
Returns a reference to the current session.
|
||||
|
||||
=cut
|
||||
|
||||
sub session {
|
||||
my $self = shift;
|
||||
return $self->{_session};
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 set ( properties )
|
||||
|
||||
Sets a variable for this workflow.
|
||||
|
||||
=head3 properties
|
||||
|
||||
A hash reference containing the properties to set.
|
||||
|
||||
=head4 title
|
||||
|
||||
A title indicating what this workflow does. It should be short and descriptive as it will appear in dropdown forms.
|
||||
|
||||
=head4 description
|
||||
|
||||
A longer description of the workflow.
|
||||
|
||||
=head4 enabled
|
||||
|
||||
A boolean indicating whether this workflow may be executed right now.
|
||||
|
||||
=head4 type
|
||||
|
||||
A string indicating the type of object this workflow will be operating on. Valid values are "None", or any object type, like "WebGUI::VersionTag".
|
||||
|
||||
=head4 mode
|
||||
|
||||
A string containing one of "singleton", "parallel", "serial", or "realtime". Parallel is the default and should be
|
||||
used in most situations. Singletons will allow only one instance of the workflow to be created at one time. New
|
||||
instances will be destroyed immediately if a one instance of a singleton already exists. Serial workflows will run
|
||||
instances sequentially in FIFO. Realtime workflows will run immediately without being handed off to Spectre for
|
||||
governance.
|
||||
|
||||
=cut
|
||||
|
||||
sub set {
|
||||
my $self = shift;
|
||||
my $properties = shift;
|
||||
|
||||
# depricated. replaced by mode.
|
||||
if ($properties->{isSerial} == 1) {
|
||||
$properties->{mode} = "serial";
|
||||
}
|
||||
if ($properties->{isSingleton} == 1) {
|
||||
$properties->{mode} = "singleton";
|
||||
}
|
||||
|
||||
$self->{_data}{mode} = $properties->{mode} || $self->{_data}{mode} || "parallel";
|
||||
$self->{_data}{enabled} = exists $properties->{enabled} ? $properties->{enabled} : $self->{_data}{enabled};
|
||||
$self->{_data}{title} = $properties->{title} || $self->{_data}{title} || "Untitled";
|
||||
$self->{_data}{description} = (exists $properties->{description}) ? $properties->{description} : $self->{_data}{description};
|
||||
$self->{_data}{type} = $properties->{type} || $self->{_data}{type} || "None";
|
||||
$self->session->db->setRow("Workflow","workflowId",$self->{_data});
|
||||
}
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<WebGUI::Workflow::Instance>
|
||||
|
||||
After creating a workflow, you need to create an instance of that workflow to kick off activities in it.
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
1;
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue