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
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;
|
|
}
|
|
}
|
|
|