Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00%
0 / 1
86.67%
13 / 15
CRAP
96.12%
99 / 103
SWNode
0.00%
0 / 1
86.67%
13 / 15
44
96.12%
99 / 103
 __construct($node, $defaultWorkflowId=null)
0.00%
0 / 1
12.02
94.44%
34 / 36
 parseNodeId($status,$workflowId)
100.00%
1 / 1
7
100.00%
16 / 16
 __get($name)
100.00%
1 / 1
3
100.00%
5 / 5
 _loadTransition($tr, $defWfId)
0.00%
0 / 1
7.04
90.91%
20 / 22
 getWorkflowId()
100.00%
1 / 1
1
100.00%
1 / 1
 getId()
100.00%
1 / 1
1
100.00%
1 / 1
 getLabel()
100.00%
1 / 1
1
100.00%
1 / 1
 getNext()
100.00%
1 / 1
1
100.00%
1 / 1
 getConstraint()
100.00%
1 / 1
1
100.00%
1 / 1
 getMetadata()
100.00%
1 / 1
1
100.00%
1 / 1
 getNextNodeIds()
100.00%
1 / 1
1
100.00%
1 / 1
 getTransitionTask($endNode)
100.00%
1 / 1
3
100.00%
8 / 8
 __toString()
100.00%
1 / 1
1
100.00%
1 / 1
 toString()
100.00%
1 / 1
1
100.00%
1 / 1
 equals($status)
100.00%
1 / 1
3
100.00%
7 / 7
<?php
/**
* This class implements a graph node for the simpleWorkflow extension.
*/
class SWNode extends CComponent
{
/**
* @var string workflow identifier
*/
private $_workflowId;
/**
* @var string node identifier which must be unique within the workflow
*/
private $_id;
/**
* @var string user friendly node name. If not provided at construction, the string
* 'workflowId/nodeId' will be used.
*/
private $_label;
/**
* @var string expression evaluated in the context of an CActiveRecord object. It must returns
* a boolean value that is used to allow access to this node.
*/
private $_constraint = array();
/**
* @var array
*/
private $_metadata = array();
/**
* @var array array of transitions that exist between this node and other nodes
*/
private $_tr=array();
/**
* Creates a workflow node instance.
* If no workflowId is specified in the nodeId, then the $defaultWorkflowId is used.<br/>
* Note that both workflow and node id must begin with a alphabetic character followed by aplha-numeric
* characters : all other characters are not accepted and cause an exception to be thrown (see {@link SWNode::parseNodeId()})
*
* @param mixed $node If a string is passed as argument, it can be both in format workflowId/NodeId
* or simply 'nodeId'. In this last case, argument $defaultWorkflowIs must be provided, otherwise it is
* ignored. <br/>
* The $node argument may also be provided as an associative array, with the following structure :<br/>
* <pre>
* {
* 'id' => string, // mandatory
* 'label' => string , // optional
* 'constraint' => string, // optional
* 'transition' => array, // optional
* 'metadata' => array, // optional
* }
* </pre>
* Again, the 'id' value may contain a workflow id (e.g 'workflowId/nodeId') but if it's not the case then
* the second argument $defaultWorkflowId must be provided.
* @param string defaultWorkflowId workflow Id that is used each time a workflow is needed to complete
* a status name.
*/
public function __construct($node, $defaultWorkflowId=null)
{
if($node==null || empty($node))
throw new SWException('illegal argument exception : $node cannot be empty', SWException::SW_ERR_CREATE_NODE);
$st=array();
if( $node instanceof SWNode )
{
// copy constructor : does not copy transitions, constraints and metadata
$this->_workflowId = $node->getWorkflowId();
$this->_id = $node->getId();
$this->_label = $node->getLabel();
$this->_metadata = $node->getMetadata();
}
else {
if( is_array($node))
{
if(!isset($node['id']))
throw new SWException('missing node id',SWException::SW_ERR_MISSING_NODE_ID);
// set node id -----------------------
$st=$this->parseNodeId($node['id'],$defaultWorkflowId);
if(isset($node['label'])){
$this->_label=$node['label'];
}
if(isset($node['constraint'])){
$this->_constraint=$node['constraint'];
}
if(isset($node['transition'])){
$this->_loadTransition($node['transition'],$st['workflow']);
}
if(isset($node['metadata'])){
$this->_metadata = $node['metadata'];
}
}
elseif(is_string($node))
{
$st=$this->parseNodeId($node,$defaultWorkflowId);
}
$this->_workflowId = $st['workflow'];
$this->_id = $st['node'];
if(!isset($this->_label))
$this->_label=$this->_id;
}
}
/**
* Parse a status name and return it as an array. The string passed as argument
* may be a complete status name (e.g workflowId/nodeId) and if no workflowId is
* specified, then an exception is thrown. Both workflow and node ids must match
* following pattern:
* <pre>
* /^[[:alpha:]][[:alnum:]_]*$/
* </pre>
* For instance :
* <ul>
* <li>ready : matches</li>
* <li>to_process : matches</li>
* <li>priority_1 : matches</li>
* <li>2_level : does not match</li>
* <li>to-production : does not match</li>
* <li>enable/disable : does not match</li>
*</ul>
* @param string status status name (wfId/nodeId or nodeId)
* @return array the complete status (e.g array ( [workflow] => 'a' [node] => 'b' ))
*/
public function parseNodeId($status,$workflowId)
{
$nodeId=$wfId=null;
if(strstr($status,'/')){
if(preg_match('/^([[:alpha:]][[:alnum:]_]*)\/([[:alpha:]][[:alnum:]_]*)$/',$status,$matches) == 1){
$wfId = $matches[1];
$nodeId = $matches[2];
}
}
else{
if(preg_match('/^[[:alpha:]][[:alnum:]_]*$/',$status) == 1){
$nodeId = $status;
if(preg_match('/^[[:alpha:]][[:alnum:]_]*$/',$workflowId) == 1){
$wfId = $workflowId;
}
}
}
if( $wfId == null || $nodeId == null){
throw new SWException('failed to create node from node Id = '.$status.', workflow Id = '.$workflowId, SWException::SW_ERR_CREATE_NODE);
}
return array('workflow'=>$wfId,'node'=>$nodeId);
}
/**
* Overrides the default magic method defined at the CComponent level in order to
* return a metadata value if parent method fails.
*
* @see CComponent::__get()
*/
public function __get($name)
{
try{
return parent::__get($name);
}catch(CException $e){
if(isset($this->_metadata[$name])){
return $this->_metadata[$name];
}else{
throw new SWException('Property "'.$name.'" is not found.',SWException::SW_ERR_ATTR_NOT_FOUND);
}
}
}
/**
* Loads the set of transitions passed as argument.
*
* @param mixed $tr if provided as a string, it is a comma separated list of SWNodes id,
* This list can also be provided as an array
* @param string $defWfId Default workflow Id if nodes have no workflow id, this value is used
* as their workflow id.
*/
private function _loadTransition($tr, $defWfId)
{
if( is_string($tr))
{
$trAr=explode(',',$tr);
foreach($trAr as $aTr)
{
$objNode=new SWNode(trim($aTr),$defWfId);
$this->_tr[$objNode->toString()]=null;
}
}
elseif( is_array($tr))
{
foreach($tr as $key => $value){
if( is_string($key)){
$objNode=new SWNode(trim($key),$defWfId);
if($value!=null)
$this->_tr[$objNode->toString()]=$value;
else
$this->_tr[$objNode->toString()]=null;
}else {
$objNode=new SWNode(trim($value),$defWfId);
$this->_tr[$objNode->toString()]=null;
}
}
}else {
throw new SWException(__FUNCTION__. 'incorrect arg type : string or array expected');
}
}
//////////////////////////////////////////////////////////////////////////////////////////
// accessors
public function getWorkflowId() {return $this->_workflowId;}
public function getId() {return $this->_id;}
public function getLabel() {return $this->_label;}
public function getNext() {return $this->_tr;}
public function getConstraint() {return $this->_constraint;}
public function getMetadata() {return $this->_metadata;}
public function getNextNodeIds() {return array_keys($this->_tr);}
/**
* @returns String the task for this transition or NULL if no task is defined
* @param mixed $endNode SWNode instance or string that will be converted to SWNode instance (e.g 'workflowId/nodeId')
* @throws SWException
*/
public function getTransitionTask($endNode){
if( ! $endNode instanceof SWNode ){
$endNode = new SWNode($endNode, $this->getWorkflowId());
}
$endNodeId = $endNode->toString();
return ( isset($this->_tr[$endNodeId])
? $this->_tr[$endNodeId]
: null
);
}
public function __toString(){
return $this->getWorkflowId().'/'.$this->getId();
}
public function toString(){
return $this->__toString();
}
/**
* SWnode comparator method. Note that only the node and the workflow id
* members are compared.
*
* @param mixed SWNode object or string. If a string is provided it is used to create
* a new SWNode object.
*/
public function equals($status){
if( $status instanceof SWNode )
{
return $status->toString() == $this->toString();
}
else try{
$other=new SWNode($status,$this->getWorkflowId());
return $other->equals($this);
}catch(Exception $e)
{
throw new SWException('comparaison error - the value passed as argument (value='.$status.') cannot be converted into a SWNode',$e->getCode());
}
}
}