2014-02-05 12:33:36 -04:00
< ? php
namespace ProcessMaker\Project\Adapter ;
use ProcessMaker\Project ;
use ProcessMaker\Util\Hash ;
2014-02-06 11:00:15 -04:00
/**
* Class BpmnWorkflow
2014-02-10 13:09:50 -04:00
*
2014-02-06 11:00:15 -04:00
* @ package ProcessMaker\Project\Adapter
2014-02-10 13:09:50 -04:00
* @ author Erik Amaru Ortiz < aortiz . erik @ gmail . com , erik @ colosa . com >
2014-02-06 11:00:15 -04:00
*/
2014-02-05 12:33:36 -04:00
class BpmnWorkflow extends Project\Bpmn
{
2014-02-06 16:21:46 -04:00
/**
* @ var \ProcessMaker\Project\Workflow
*/
protected $wp ;
2014-02-21 19:26:55 -04:00
const BPMN_GATEWAY_COMPLEX = " COMPLEX " ;
const BPMN_GATEWAY_PARALLEL = " PARALLEL " ;
const BPMN_GATEWAY_INCLUSIVE = " INCLUSIVE " ;
const BPMN_GATEWAY_EXCLUSIVE = " EXCLUSIVE " ;
2014-02-05 14:09:48 -04:00
/**
* OVERRIDES
*/
2014-02-05 12:33:36 -04:00
2014-02-06 16:21:46 -04:00
public static function load ( $prjUid )
{
2014-02-13 16:40:00 -04:00
2014-02-06 16:21:46 -04:00
$parent = parent :: load ( $prjUid );
2014-02-13 16:40:00 -04:00
//return new BpmnWorkflow();
2014-02-06 16:21:46 -04:00
2014-02-13 16:40:00 -04:00
$me = new BpmnWorkflow ();
2014-02-06 16:21:46 -04:00
$me -> project = $parent -> project ;
$me -> prjUid = $parent -> project -> getPrjUid ();
$me -> wp = Project\Workflow :: load ( $me -> prjUid );
return $me ;
}
2014-02-05 14:09:48 -04:00
public function create ( $data )
{
try {
parent :: create ( $data );
} catch ( \Exception $e ) {
throw new \RuntimeException ( sprintf ( " Can't create Bpmn Project. " . PHP_EOL . $e -> getMessage ()));
}
try {
$wpData = array ();
$wpData [ " PRO_UID " ] = $this -> getUid ();
if ( array_key_exists ( " PRJ_NAME " , $data )) {
$wpData [ " PRO_TITLE " ] = $data [ " PRJ_NAME " ];
}
if ( array_key_exists ( " PRJ_DESCRIPTION " , $data )) {
$wpData [ " PRO_DESCRIPTION " ] = $data [ " PRJ_DESCRIPTION " ];
}
if ( array_key_exists ( " PRJ_AUTHOR " , $data )) {
$wpData [ " PRO_CREATE_USER " ] = $data [ " PRJ_AUTHOR " ];
}
2014-02-10 16:35:24 -04:00
$this -> wp = new Project\Workflow ();
$this -> wp -> create ( $wpData );
2014-02-05 14:09:48 -04:00
} catch ( \Exception $e ) {
$prjUid = $this -> getUid ();
$this -> remove ();
throw new \RuntimeException ( sprintf (
" Can't create Bpmn Project with prj_uid: %s, workflow creation fails. " . PHP_EOL . $e -> getMessage ()
, $prjUid
));
}
}
public static function getList ( $start = null , $limit = null , $filter = " " , $changeCaseTo = CASE_UPPER )
{
2014-02-26 12:53:17 -04:00
$bpmnProjects = parent :: getList ( $start , $limit , $filter );
$workflowProjects = Project\Workflow :: getList ( $start , $limit , $filter );
$bpmnProjectsUid = array ();
$bpmnProjectsList = array ();
$list = array ();
2014-02-05 14:09:48 -04:00
2014-02-26 12:53:17 -04:00
foreach ( $bpmnProjects as $bpmnProject ) {
$bpmnProjectsList [ $bpmnProject [ " PRJ_UID " ]] = $bpmnProject ;
2014-02-05 14:09:48 -04:00
}
2014-02-26 12:53:17 -04:00
$bpmnProjectsUid = array_keys ( $bpmnProjectsList );
2014-02-05 14:09:48 -04:00
2014-02-26 12:53:17 -04:00
foreach ( $workflowProjects as $workflowProject ) {
$data [ " PRJ_UID " ] = $workflowProject [ " PRO_UID " ];
$data [ " PRJ_NAME " ] = $workflowProject [ " PRO_TITLE " ];
$data [ " PRJ_DESCRIPTION " ] = $workflowProject [ " PRO_DESCRIPTION " ];
$data [ " PRJ_CATEGORY " ] = $workflowProject [ " PRO_CATEGORY " ];
if ( in_array ( $workflowProject [ " PRO_UID " ], $bpmnProjectsUid )) {
$data [ " PRJ_TYPE " ] = " bpmn " ;
$data [ " PRJ_CREATE_DATE " ] = $bpmnProjectsList [ $workflowProject [ " PRO_UID " ]][ " PRJ_CREATE_DATE " ];
$data [ " PRJ_UPDATE_DATE " ] = $bpmnProjectsList [ $workflowProject [ " PRO_UID " ]][ " PRJ_UPDATE_DATE " ];
} else {
$data [ " PRJ_TYPE " ] = " classic " ;
$data [ " PRJ_CREATE_DATE " ] = $workflowProject [ " PRO_CREATE_DATE " ];
$data [ " PRJ_UPDATE_DATE " ] = $workflowProject [ " PRO_UPDATE_DATE " ];
2014-02-05 14:09:48 -04:00
}
2014-02-26 12:53:17 -04:00
if ( $changeCaseTo != CASE_UPPER ) {
$data = array_change_key_case ( $data , $changeCaseTo );
}
$list [] = $data ;
2014-02-05 14:09:48 -04:00
}
return $list ;
}
2014-02-06 16:21:46 -04:00
public function addActivity ( $data )
{
$taskData = array ();
2014-02-10 16:35:24 -04:00
2014-02-24 19:10:45 -04:00
$actUid = parent :: addActivity ( $data );
$taskData [ " TAS_UID " ] = $actUid ;
2014-02-06 16:21:46 -04:00
if ( array_key_exists ( " ACT_NAME " , $data )) {
$taskData [ " TAS_TITLE " ] = $data [ " ACT_NAME " ];
}
if ( array_key_exists ( " ACT_NAME " , $data )) {
$taskData [ " TAS_POSX " ] = $data [ " BOU_X " ];
}
if ( array_key_exists ( " ACT_NAME " , $data )) {
$taskData [ " TAS_POSY " ] = $data [ " BOU_Y " ];
}
$this -> wp -> addTask ( $taskData );
2014-02-24 19:10:45 -04:00
return $actUid ;
2014-02-06 16:21:46 -04:00
}
2014-02-06 19:17:11 -04:00
public function updateActivity ( $actUid , $data )
{
parent :: updateActivity ( $actUid , $data );
$taskData = array ();
if ( array_key_exists ( " ACT_NAME " , $data )) {
$taskData [ " TAS_TITLE " ] = $data [ " ACT_NAME " ];
}
if ( array_key_exists ( " ACT_NAME " , $data )) {
$taskData [ " TAS_POSX " ] = $data [ " BOU_X " ];
}
if ( array_key_exists ( " ACT_NAME " , $data )) {
$taskData [ " TAS_POSY " ] = $data [ " BOU_Y " ];
}
$this -> wp -> updateTask ( $actUid , $taskData );
}
2014-02-06 16:21:46 -04:00
public function removeActivity ( $actUid )
{
parent :: removeActivity ( $actUid );
$this -> wp -> removeTask ( $actUid );
}
2014-02-06 21:26:06 -04:00
2014-02-24 19:58:32 -04:00
public function removeGateway ( $gatUid )
{
2014-02-25 13:47:59 -04:00
// $gatewayData = $this->getGateway($gatUid);
// $flowsDest = \BpmnFlow::findAllBy(\BpmnFlowPeer::FLO_ELEMENT_DEST, $gatUid);
// foreach ($flowsDest as $flowDest) {
// switch ($flowDest->getFloElementOriginType()) {
// case "bpmnActivity":
// $actUid = $flowDest->getFloElementOrigin();
// $flowsOrigin = \BpmnFlow::findAllBy(\BpmnFlowPeer::FLO_ELEMENT_ORIGIN, $gatUid);
//
// foreach ($flowsOrigin as $flowOrigin) {
// switch ($flowOrigin->getFloElementDestType()) {
// case "bpmnActivity":
// $toActUid = $flowOrigin->getFloElementDest();
// $this->wp->removeRouteFromTo($actUid, $toActUid);
// break;
// }
// }
// break;
// }
// }
2014-02-24 19:58:32 -04:00
parent :: removeGateway ( $gatUid );
}
2014-02-24 19:10:45 -04:00
// public function addFlow($data)
// {
// parent::addFlow($data);
2014-02-06 21:26:06 -04:00
2014-02-10 19:43:54 -04:00
// to add a workflow route
// - activity -> activity ==> route
// - activity -> gateway -> activity ==> selection, evaluation, parallel or parallel by evaluation route
2014-02-24 19:10:45 -04:00
// $routes = self::mapBpmnFlowsToWorkflowRoute($data, $flows);
//
// if ($routes !== null) {
// foreach ($routes as $routeData) {
// $this->wp->addRoute($routeData["from"], $routeData["to"], $routeData["type"]);
// }
//
// return true;
// }
//
// // to add start event->activity as initial or end task
// switch ($data["FLO_ELEMENT_ORIGIN_TYPE"]) {
// case "bpmnEvent":
// switch ($data["FLO_ELEMENT_DEST_TYPE"]) {
// case "bpmnActivity":
// $event = \BpmnEventPeer::retrieveByPK($data["FLO_ELEMENT_ORIGIN"]);
//
// switch ($event && $event->getEvnType()) {
// case "START":
// // then set that activity/task as "Start Task"
// $this->wp->setStartTask($data["FLO_ELEMENT_DEST"]);
// break;
// }
// break;
// }
// break;
// }
2014-02-06 21:26:06 -04:00
2014-02-24 19:10:45 -04:00
// }
2014-02-18 17:41:45 -04:00
2014-02-24 19:10:45 -04:00
// public function updateFlow($floUid, $data, $flows)
// {
// parent::updateFlow($floUid, $data);
// }
2014-02-18 17:41:45 -04:00
2014-02-12 17:01:19 -04:00
public function removeFlow ( $floUid )
{
2014-02-13 16:40:00 -04:00
$flow = \BpmnFlowPeer :: retrieveByPK ( $floUid );
2014-02-12 17:01:19 -04:00
parent :: removeFlow ( $floUid );
2014-02-13 16:40:00 -04:00
// verify case: event(start) -> activity
// => find the corresponding task and unset it as start task
if ( $flow -> getFloElementOriginType () == " bpmnEvent " &&
$flow -> getFloElementDestType () == " bpmnActivity "
) {
$event = \BpmnEventPeer :: retrieveByPK ( $flow -> getFloElementOrigin ());
if ( ! is_null ( $event ) && $event -> getEvnType () == " START " ) {
$activity = \BpmnActivityPeer :: retrieveByPK ( $flow -> getFloElementDest ());
$this -> wp -> setStartTask ( $activity -> getActUid (), false );
}
} elseif ( $flow -> getFloElementOriginType () == " bpmnActivity " &&
$flow -> getFloElementDestType () == " bpmnEvent " ) {
// verify case: activity -> event(end)
// => find the corresponding task and unset it as start task
$event = \BpmnEventPeer :: retrieveByPK ( $flow -> getFloElementDest ());
if ( ! is_null ( $event ) && $event -> getEvnType () == " END " ) {
$activity = \BpmnActivityPeer :: retrieveByPK ( $flow -> getFloElementOrigin ());
if ( ! is_null ( $activity )) {
$this -> wp -> setEndTask ( $activity -> getActUid (), false );
}
}
2014-02-24 19:10:45 -04:00
} else {
switch ( $flow -> getFloElementOriginType ()) {
case " bpmnActivity " :
switch ( $flow -> getFloElementDestType ()) {
// activity->activity
case " bpmnActivity " :
$this -> wp -> removeRouteFromTo ( $flow -> getFloElementOrigin (), $flow -> getFloElementDest ());
break ;
}
break ;
}
2014-02-13 16:40:00 -04:00
}
2014-02-24 19:10:45 -04:00
// TODO Complete for other routes, activity->activity, activity->gateway and viceversa
2014-02-12 17:01:19 -04:00
}
2014-02-07 08:41:11 -04:00
2014-02-10 19:43:54 -04:00
public function addEvent ( $data )
{
if ( ! array_key_exists ( " EVN_TYPE " , $data )) {
throw new \RuntimeException ( " Required param \" EVN_TYPE \" is missing. " );
}
parent :: addEvent ( $data );
}
2014-02-24 19:10:45 -04:00
public function mapBpmnFlowsToWorkflowRoutes ()
2014-02-10 19:43:54 -04:00
{
2014-02-24 19:10:45 -04:00
$activities = $this -> getActivities ();
foreach ( $activities as $activity ) {
2014-02-10 19:43:54 -04:00
2014-02-24 19:10:45 -04:00
$flows = \BpmnFlow :: findAllBy ( array (
\BpmnFlowPeer :: FLO_ELEMENT_ORIGIN => $activity [ " ACT_UID " ],
\BpmnFlowPeer :: FLO_ELEMENT_ORIGIN_TYPE => " bpmnActivity "
));
//
foreach ( $flows as $flow ) {
switch ( $flow -> getFloElementDestType ()) {
case " bpmnActivity " :
// (activity -> activity)
$this -> wp -> addRoute ( $activity [ " ACT_UID " ], $flow -> getFloElementDest (), " SEQUENTIAL " );
break ;
case " bpmnGateway " :
// (activity -> gateway)
// we must find the related flows: gateway -> <object>
$gatUid = $flow -> getFloElementDest ();
$gatewayFlows = \BpmnFlow :: findAllBy ( array (
\BpmnFlowPeer :: FLO_ELEMENT_ORIGIN => $gatUid ,
\BpmnFlowPeer :: FLO_ELEMENT_ORIGIN_TYPE => " bpmnGateway "
));
2014-02-25 13:47:59 -04:00
if ( $gatewayFlows > 0 ) {
$this -> wp -> resetTaskRoutes ( $activity [ " ACT_UID " ]);
}
2014-02-24 19:10:45 -04:00
foreach ( $gatewayFlows as $gatewayFlow ) {
$gatewayFlow = $gatewayFlow -> toArray ();
switch ( $gatewayFlow [ 'FLO_ELEMENT_DEST_TYPE' ]) {
case 'bpmnActivity' :
// (gateway -> activity)
$gateway = \BpmnGateway :: findOneBy ( \BpmnGatewayPeer :: GAT_UID , $gatUid ) -> toArray ();
switch ( $gateway [ " GAT_TYPE " ]) {
//case 'SELECTION':
case self :: BPMN_GATEWAY_COMPLEX :
$routeType = " SELECT " ;
break ;
//case 'EVALUATION':
case self :: BPMN_GATEWAY_EXCLUSIVE :
$routeType = " EVALUATE " ;
break ;
//case 'PARALLEL':
case self :: BPMN_GATEWAY_PARALLEL :
if ( $gateway [ " GAT_DIRECTION " ] == " DIVERGING " ) {
$routeType = " PARALLEL " ;
} elseif ( $gateway [ " GAT_DIRECTION " ] == " CONVERGING " ) {
$routeType = " SEC-JOIN " ;
} else {
throw new \LogicException ( sprintf (
" Invalid Gateway direction, accepted values: [%s|%s], given: %s. " ,
" DIVERGING " , " CONVERGING " , $gateway [ " GAT_DIRECTION " ]
));
}
break ;
//case 'PARALLEL_EVALUATION':
case self :: BPMN_GATEWAY_INCLUSIVE :
if ( $gateway [ " GAT_DIRECTION " ] == " DIVERGING " ) {
$routeType = " PARALLEL-BY-EVALUATION " ;
} elseif ( $gateway [ " GAT_DIRECTION " ] == " CONVERGING " ) {
$routeType = " SEC-JOIN " ;
} else {
throw new \LogicException ( sprintf (
" Invalid Gateway direction, accepted values: [%s|%s], given: %s. " ,
" DIVERGING " , " CONVERGING " , $gateway [ " GAT_DIRECTION " ]
));
}
break ;
// case 'PARALLEL_JOIN':
// $routeType = 'SEC-JOIN';
// break;
default :
throw new \LogicException ( sprintf ( " Unsupported Gateway type: %s " , $gateway [ 'GAT_TYPE' ]));
}
2014-02-26 17:38:07 -04:00
$condition = array_key_exists ( 'FLO_CONDITION' , $gatewayFlow ) ? $gatewayFlow [ " FLO_CONDITION " ] : '' ;
2014-02-24 19:10:45 -04:00
2014-02-26 17:38:07 -04:00
$this -> wp -> addRoute ( $activity [ " ACT_UID " ], $gatewayFlow [ 'FLO_ELEMENT_DEST' ], $routeType , $condition );
2014-02-24 19:10:45 -04:00
break ;
default :
// for processmaker is only allowed flows between "gateway -> activity"
// any another flow is considered invalid
throw new \LogicException ( sprintf (
" For ProcessMaker is only allowed flows between \" gateway -> activity \" " . PHP_EOL .
" Given: bpmnGateway -> " . $gatewayFlow [ 'FLO_ELEMENT_DEST_TYPE' ]
));
}
}
break ;
}
}
}
2014-02-06 21:26:06 -04:00
}
2014-02-07 08:41:11 -04:00
2014-02-26 17:38:07 -04:00
// public static function mapBpmnFlowsToWorkflowRoute2($flow, $flows, $gateways, $events)
// {
// $fromUid = $flow['FLO_ELEMENT_ORIGIN'];
// $result = array();
//
// if ($flow['FLO_ELEMENT_ORIGIN_TYPE'] != "bpmnActivity") {
// // skip flows that comes from a element that is not an Activity
// self::log("Skip map FlowsToWorkflowRoute for -> flow with FLO_UID: {$flow['FLO_UID']}, that have FLO_ELEMENT_ORIGIN: {$flow['FLO_ELEMENT_ORIGIN_TYPE']}:$fromUid");
// return null;
// }
//
// if ($flow['FLO_TYPE'] != 'SEQUENCE') {
// throw new \LogicException(sprintf(
// "Unsupported flow type: %s, ProcessMaker only support type '', Given: '%s'",
// 'SEQUENCE', $flow['FLO_TYPE']
// ));
// }
//
// switch ($flow['FLO_ELEMENT_DEST_TYPE']) {
// case 'bpmnActivity':
// // the most easy case, when the flow is connecting a activity with another activity
// $result[] = array("from" => $fromUid, "to" => $flow['FLO_ELEMENT_DEST'], "type" => 'SEQUENTIAL');
// break;
// case 'bpmnGateway':
// $gatUid = $flow['FLO_ELEMENT_DEST'];
//
// // if it is a gateway it can fork one or more routes
// $gatFlows = self::findInArray($gatUid, "FLO_ELEMENT_ORIGIN", $flows);
//
// foreach ($gatFlows as $gatFlow) {
// switch ($gatFlow['FLO_ELEMENT_DEST_TYPE']) {
// case 'bpmnActivity':
// // getting gateway properties
// $gateways = self::findInArray($gatUid, "GAT_UID", $gateways);
//
// if (! empty($gateways)) {
// $gateway = $gateways[0];
// $routeType = "";
//
// switch ($gateway['GAT_TYPE']) {
// case self::BPMN_GATEWAY_COMPLEX:
// $routeType = 'SELECT';
// break;
// case self::BPMN_GATEWAY_EXCLUSIVE:
// $routeType = 'EVALUATE';
// break;
// case self::BPMN_GATEWAY_INCLUSIVE:
// switch ($gateway['GAT_DIRECTION']) {
// case "DIVERGING":
// $routeType = 'PARALLEL-BY-EVALUATION';
// break;
// case "CONVERGING":
// $routeType = 'SEC-JOIN';
// break;
// default:
// throw new \LogicException(sprintf("Unsupported Gateway direction: %s", $gateway['GAT_DIRECTION']));
// }
// break;
// case self::BPMN_GATEWAY_PARALLEL:
// switch ($gateway['GAT_DIRECTION']) {
// case "DIVERGING":
// $routeType = 'PARALLEL';
// break;
// case "CONVERGING":
// $routeType = 'SEC-JOIN';
// break;
// default:
// throw new \LogicException(sprintf("Unsupported Gateway direction: %s", $gateway['GAT_DIRECTION']));
// }
// break;
// default:
// throw new \LogicException(sprintf("Unsupported Gateway type: %s", $gateway['GAT_TYPE']));
// }
//
// $result[] = array("from" => $fromUid, "to" => $gatFlow['FLO_ELEMENT_DEST'], "type" => $routeType);
// }
// break;
// default:
// // for processmaker is only allowed flows between "gateway -> activity"
// // any another flow is considered invalid
// throw new \LogicException(sprintf(
// "For ProcessMaker is only allowed flows between \"gateway -> activity\" " . PHP_EOL .
// "Given: bpmnGateway -> " . $gatFlow['FLO_ELEMENT_DEST_TYPE']
// ));
// }
// }
// break;
// case 'bpmnEvent':
// $evnUid = $flow['FLO_ELEMENT_DEST'];
// $events = self::findInArray($evnUid, "EVN_UID", $events);
//
//
// if (! empty($events)) {
// $event = $events[0];
//
// switch ($event['EVN_TYPE']) {
// case 'END':
// $routeType = 'SEQUENTIAL';
// $result[] = array("from" => $fromUid, "to" => "-1", "type" => $routeType);
// break;
// default:
// throw new \LogicException("Invalid connection to Event object type");
// }
// }
// break;
// }
//
// return empty($result) ? null : $result;
// }
2014-02-07 08:41:11 -04:00
2014-02-10 16:35:24 -04:00
public function remove ()
{
parent :: remove ();
$this -> wp -> remove ();
}
2014-02-13 16:40:00 -04:00
2014-02-05 12:33:36 -04:00
}