You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

464 lines
13 KiB

<?php
error_reporting(E_ALL);
ini_set("display_errors", "on");
class WorkFlowParser
{
private $flowList;
private $flowInfo;
private $traversalMark = array(); //遍历标记private $count=0;
private $count = 0;
private $edgeTo = array();
private $sourceId; //图遍历使用
private $targetId; //图遍历使用
/**
* @param String system_ID
* @param Stirng pFlowId
*/
public function __construct($systemId, $flowId)
{
//加载流程文件
list($wf_file) = DB::fields(" select wf_file from workflow_items
where SYSTEM_ID='$systemId' and FLOW_ID='$flowId'");
// echo $wf_file;
$flowchart = json_decode(file_get_contents($wf_file), true);
//var_dump( file_get_contents("../".$wf_file) );
// var_dump( $flowchart);
$this->flowList = $flowchart['flowList'];
$this->flowInfo = array(
'flowName' => $flowchart['flowName'],
'systemId' => $flowchart['systemId'],
'flowId' => $flowchart['flowId'],
'version' => $flowchart['version']
);
foreach ($this->flowList as $key => $val) {
$this->edgeTo[$key] = 0;
$this->traversalMark[$key] = false;
}
}
/**
* 获取第一个节点
*/
public function getFirstNode()
{
$firstNodeId = $this->_getFirstNodeId();
if (empty($firstNodeId)) {
return null;
}
$nodeClass = Node::$nodeClasses[strtoupper($this->flowList[$firstNodeId]['nodeType'])];
return new $nodeClass($this->flowList[$firstNodeId]);
}
/**
*
*/
private function _getFirstNodeId()
{
if (empty($this->flowList)) {
return null;
}
foreach ($this->flowList as $domId => $node) {
if (substr($domId, 0, 5) == 'start') {
return $domId;
}
}
}
/***
* 获取某节点的父节点数组
*
*
*/
function getParentNodes($nodeId)
{
$_nodes = array();
if (empty($this->flowList)) {
return $_nodes;
}
foreach ($this->flowList as $domId => $node) {
if (in_array($node['targetId'], $nodeId)) {
array_push($_nodes, $this->getNode($node));
}
}
return $_nodes;
}
/**
* 获取前一层所有节点
* @param String nodeId 节点ID
* @param String nodeType 节点类型
* @return Array [TASK_NODE=>['',.....],
* LOGIC_NODE=>['',.....],
* SPLIT_NODE=>['',.....]
* ]
*/
public function getPrevLevelNodes($nodeId, $nodeType = Node::ALL_NODE)
{
$_nodes = array();
if (empty($this->flowList) || !array_key_exists($nodeId, $this->flowList)) {
return $_nodes;
}
foreach ($this->flowList as $domId => $node) {
//如果表中节点的目标节点中包含参数节点
if (in_array($nodeId, $node['targetId'])) {
//获取节点类型
$currentNodeType = array_search(ucfirst($node['nodeType']), Node::$nodeClasses);
foreach (Node::$nodeTypes as $types) {
//如果匹配到上层有匹配的节点
if (($currentNodeType == ($nodeType & $types))) {
$_nodes[$currentNodeType][] = $this->getNode($node);
}
}
}
}
return $_nodes;
}
/**
* 获取同一层的所有节点
* @param String nodeId 节点ID
* @param String nodeType 节点类型
* @return Array [TASK_NODE=>['',.....],
* LOGIC_NODE=>['',.....],
* SPLIT_NODE=>['',.....]
* ]
*/
private function getSameLevelNodes($nodeId, $nodeType = Node::ALL_NODE)
{
$_nodes = array();
if (empty($this->flowList) || !array_key_exists($nodeId, $this->flowList)) {
return _nodes;
}
$_parentNodes = $this->getPrevLevelNodes($nodeId, $nodeType);
if (count($_parentNodes) == 0) {
return $_nodes;
}
//如果有多个父节点,说明当前这层只有一个节点
if (count($_parentNodes) >= 2) {
$currentNodeType = array_search(
ucfirst($this->flowList[$nodeId]['nodeType']),
Node::$nodeClasses
);
foreach (Node::$nodeTypes as $types) {
if (($currentNodeType == ($nodeType & $types))) {
$_nodes[$currentNodeType][] = $this->getNode($this->flowList[$nodeId]);
}
}
return $_nodes;
}
//如果只有一个父节点,遍历该父节点的所有节点
$pNode = $_parentNodes[0];
return $this->getNextLevelNodes($pNode->getNodeId(), $nodeType);
}
/**
* 获取下一层的所有节点
* @param String nodeId 节点ID
* @param String nodeType 节点类型
* @return Array [TASK_NODE=>['',.....],
* LOGIC_NODE=>['',.....],
* SPLIT_NODE=>['',.....]
* ]
*/
public function getNextLevelNodes($nodeId, $nodeType = Node::ALL_NODE)
{
if (empty($this->flowList) || !array_key_exists($nodeId, $this->flowList)) {
return null;
}
$_nodes = array();
$nextLevelIDs = $this->flowList[$nodeId]["targetId"];
foreach ($nextLevelIDs as $nextId) {
$currentNodeType = array_search(
strtoupper($this->flowList[$nextId]['nodeType']),
Node::$nodeTypes
);
// echo " nextId :" . var_dump( $currentNodeType);
// var_dump(strtoupper ($this->flowList[$nextId]['nodeType']));
// var_dump($currentNodeType);
$nodeType = is_array($nodeType) ? $nodeType : [$nodeType];
if ($currentNodeType && in_array(strtoupper(Node::$nodeTypes[$currentNodeType]), $nodeType)) {
$_nodes[strtoupper(Node::$nodeTypes[$currentNodeType])][] = $this->getNode($this->flowList[$nextId]);
}
}
return $_nodes;
}
/**
* @param String code 节点flowCode
* @param String nodeType 节点类型
* @return Array [TASK_NODE=>['',.....],
* LOGIC_NODE=>['',.....],
* SPLIT_NODE=>['',.....]
* ]
*/
function getNextNodes($code, $nodeType = Node::ALL_NODE)
{
$node = $this->getNodeByCode($code);
// var_dump($node);
// var_dump($this->getNextLevelNodes($node->getNodeId(), $nodeType));
return $this->getNextLevelNodes($node->getNodeId(), $nodeType);
}
/**
* 获取最后节点,如果nodeId不未 空,则获取nodeId所在流程的所有结案节点
* @param String nodeId
* @return Array 结案节点的集合
*/
function getFinalCodes()
{
$arrNode = array();
if (empty($this->flowList)) {
return null;
}
foreach ($this->flowList as $domId => $node) {
if (substr($domId, 0, 3) == 'end') {
array_push($arrNode, $node['flowCode']);
}
}
return $arrNode;
}
public function getNodeIdByCode($code)
{
$node = $this->getNodeByCode($code);
if (!empty($node)) {
return $node->getNodeId();
}
return null;
}
/***
* 根据nodeId 获取Code
*
* @param $nodeId
* @return null|*Node
*/
public function getNodeCodeByKey($nodeId)
{
if (empty($this->flowList) || !array_key_exists($nodeId, $this->flowList)) {
return null;
}
return $this->flowList[$nodeId]['flowCode'];
}
private function loadGraphByJson()
{
}
/**
* 根据nodeId获取对应的节点
* @param $node
* @return mixed
*/
public function getNode($node)
{
try {
// var_dump($node);
// var_dump($node['nodeType']);
$_nodeClass = Node::$nodeClasses[strtoupper($node['nodeType'])];
// var_dump(strtoupper(Node::$nodeClasses[$node['nodeType']]));
return new $_nodeClass($node);
// exit();
} catch (Exception $exception) {
// var_dump(strtoupper(Node::$nodeClasses[$node['nodeType']]));
echo $exception->getMessage();
}
}
/***
*根据Key值获取节点对象
* @param $nodeId
* @return mixed|null
*/
public function getNodeByNodeId($nodeId)
{
if (empty($this->flowList) || !array_key_exists($nodeId, $this->flowList)) {
return null;
}
$_node = $this->flowList[$nodeId];
return $this->getNode($_node);
}
/***
*根据Code值获取节点对象
* @param $code
* @return mixed|null
*/
public function getNodeByCode($code)
{
if (empty($this->flowList)) {
return null;
}
foreach ($this->flowList as $domId => $node) {
if (array_key_exists('flowCode', $node) and $node['flowCode'] == $code) {
return $this->getNodeByNodeId($node['nodeId']);
}
}
return null;
}
public function getAllNode($nodeType = Node::ALL_NODE)
{
if (empty($this->flowList)) {
return null;
}
$_nodes = array();
foreach ($this->flowList as $domId => $node) {
$currentNodeType = array_search(
strtoupper($node['nodeType']),
Node::$nodeClasses
);
// var_dump($currentNodeType);
if ($currentNodeType && !empty($currentNodeType)) {
$_nodes[Node::$nodeTypes[strtoupper($currentNodeType)]][] = $this->getNode($node);
}
}
return $_nodes;
}
/**
* 获取流程的信息
* @return array
*/
public function getFlowInfo()
{
return $this->flowInfo;
}
/**
* 获取两个节点之间的最短 长度
* @param null $targetId
* @param null $sourceId
* @return array|null
*/
public function getMinLengthBetweenNode($targetId = null, $sourceId = null)
{
if (empty($targetId)) return null;
$this->sourceId = (empty($sourceId) ? $this->_getFirstNodeId() : $sourceId);
$this->BreadthFirstSearchPaths();
return $this->pathTo($targetId);
}
/**
* 使用深度优先获取路径
*/
function DepthFirstSearchPaths()
{
//重置计数
$this->traversalMark = array();
$this->count = 0;
foreach ($this->flowList as $key => $val) {
$this->traversalMark[$key] = false;
$this->edgeTo[$key] = 0;
}
$_id = empty($this->sourceId) ? $this->_getFirstNodeId() : $this->sourceId; //$edgeTo
$this->dfs($_id);
}
/**
* 使用广度优先获取路径
*/
function BreadthFirstSearchPaths()
{
//重置计数
$this->traversalMark = array();
$this->count = 0;
foreach ($this->flowList as $key => $val) {
$this->traversalMark[$key] = false;
$this->edgeTo[$key] = 0;
}
$_id = empty($this->sourceId) ? $this->_getFirstNodeId() : $this->sourceId; //$edgeTo
$this->bfs($_id);
}
/**
* 深度优先遍历
* @param $v
*/
private function dfs($v)
{
$this->count++;
$this->traversalMark[$v] = true;
$target = $this->flowList[$v]["targetId"];
foreach ($target as $_id) {
if (empty($this->traversalMark[$_id])) {
$this->edgeTo[$_id] = $v;
$this->dfs($_id);
}
}
}
/**
* 广度优先遍历
*/
private function bfs($v)
{
$queue = array();
array_push($queue, $v);
$this->traversalMark[$v] = true;
while (count($queue) > 0) {
$_id = array_shift($queue);
$target = $this->flowList[$_id]["targetId"];
foreach ($target as $n_id) {
if (empty($this->traversalMark[$n_id])) {
$this->edgeTo[$n_id] = $_id;
$this->traversalMark[$n_id] = true;
array_push($queue, $n_id);
}
}
}
}
/**
* 判断是否有路径
* @param $v
* @return mixed
*/
private function hasPathTo($v)
{
return $this->traversalMark[$v];
}
function pathTo($v)
{
if (!$this->hasPathTo($v)) {
return array();
}
$stack = array();
try {
for ($x = $v; $x != $this->sourceId; $x = $this->edgeTo[$x]) {
array_push($stack, $x);
}
} catch (Exception $exception) {
echo $exception->getMessage();
}
// array_push($stack, $this->sourceId);
return $stack;
}
}