Node Process is a small procedural like program executable on top of php.
composer require skrip42/node-processor
- ComonNodes
- Creating user node
Node Process is a small procedural like program executable on top of php. The process consists of nodes and the connections between them, as well as the state of these nodes An important consequence of this: At any time, the process can be stopped, saved with the current state and continue to execute from the same point. Processes can be dynamically created using PHP, serialize, deserialize.
Add
use Skrip42\NodeProcessor\Process;on top of your file. You can also add all the nodes that you intend to use:
use Skrip42\NodeProcessor\Node\Other\ValueNode;
use Skrip42\NodeProcessor\Node\Logical\CompareNode;This section is presented to understand the processes, the recommended way to create processes is process builder.
$process = new Process; //create new process;
//create all necessary nodes:
// as syntax: process->createNode($nodeClassName, ...$values) : NodeAbstract
$valNode1 = $process->createNode(ValueNode::class, 1); //you can pass start parameters to the node if required
$valNode2 = $process->createNode(ValueNode::class, 5);
$compareNode = $process->createNode(ValueNode::class);
//You do not need to create a start and end node, they are already included in the process
//link nodes:
// as syntax: process->linkNode($outputNodeName, $outputNode, $inputNodeName, $inputNode)
$process->linkNode('out1', $process->getBeginNode(), 'emit', $valNode1); // you can get begin and end node
// from getBeginNode and getEndNode methods
$process->linkNode('out2', $process->getBeginNode(), 'emit', $valNode2);
$process->linkNode('out', $valNode1, 'in1', $compareNode);
$process->linkNode('out', $valNode2, 'in2', $compareNode);
$process->linkNode('more', $compareNode, 'more', $process->getEndNode()); // end node has dynamically input name
$process->linkNode('less', $compareNode, 'less', $process->getEndNode());
//You can always leave output nodes empty; can input be left blank determined by node policyThe resulting process can be represented graphically:
┌───────────────┐
┌─emit┤ ValueNode = 1 ├out─┐ ┌─────────────┐ ┌─────────┐
┌───────────┐ │ └───────────────┘ └─in1┤ ├more────more┤ │
│ ├out1─┘ │ │ │ EndNode │
│ BeginNode │ │ CompareNode ├less────less┤ │
│ ├out2─┐ │ │ └─────────┘
└───────────┘ │ ┌───────────────┐ ┌─in2┤ ├equal─X
└─emit┤ ValueNode = 5 ├out─┘ └─────────────┘
└───────────────┘
Most nodes have one or more inputs and outputs. The names of the inputs and outputs of standard bonds can be found in the documentation
For start process:
$result = $process->run(); // running process
$state = $process->getState(); // you also can get current process state for debug you scriptYou will get array of the form:
[
'status' => currentProcessStatus,
'output' => [ .. array of end node inputs .. ]
'requests' => [ .. array of requests .. ]
]status is number indicating the current state of the process
- Process::STATUS_REDY - redy to run
- Process::STATUS_RUNN - running
- Process::STATUS_ERROR - complete with error
- Process::STATUS_WAIT_RESPONSE - wait response (see Request/Response)
- Process::STATUS_COMPLETE - complete
output is array of EndNode inputs. Input name map to array key.
requests is array of request (see Request/Response)
$process->getState() - return current state of process, all process nodes, all nodes inputs and outputs After the node identifier and the names of its inputs and outputs, you can see the number of starts of the nodes, how many times each input received a signal and how many times each output emitted a signal
You can serialize and deserialize process as default php tools:
$serialized = serialize($process);
$process = unserialize($serialized);You should not include other objects in the nodes or pass from as parameters if you do not want to serialize them!
A more convenient way to create a process is through the process builder. The previous process could be created like this:
$process = Process::build(
[
'node' => [
'vn1' => [ValueNode::class, 1],
'vn2' => [ValueNode::class, 5],
'cn' => [CompareNode::class],
],
'link' => [
['out1', 'begin', 'emit', 'vn1'], //begin is the predefined start node name
['out2', 'begin', 'emit', 'vn2'],
['out', 'vn1', 'in1', 'cn'],
['out', 'vn2', 'in2', 'cn'],
['less', 'cn', 'less', 'end'], //end is the predefined end node name
['more', 'vn2', 'more', 'end'],
]
]
);using the builder you can also parameterize your process:
$process = Process::build(
[
'node' => [
'vn1' => [ValueNode::class, '{$val1}'], // template syntax: {$valueName}
'vn2' => [ValueNode::class, '{$val2}'],
'cn' => [CompareNode::class],
],
'link' => [
['out1', 'begin', 'emit', 'vn1'], //begin is the predefined start node name
['out2', 'begin', 'emit', 'vn2'],
['out', 'vn1', 'in1', 'cn'],
['out', 'vn2', 'in2', 'cn'],
['less', 'cn', 'less', 'end'], //end is the predefined end node name
['more', 'vn2', 'more', 'end'],
]
],
[ //value list
'val1' => 1,
'val2' => 5
]
);To communicate external code in the processes provided request/response system Some node can send request to process. Then the process will return with the status “waiting for a response” and as a result there will be a list of requests of the form:
[
['uniqIdOfRequest' => 'request data'],
.......
]You can send an answer like:
$process->setResponse('uniqIdOfRequest', 'response data');Then the process will continue to execute from the node that sent the request (from node "setResponse" method)
Nodes are the buildeing blocks of processes. Most nodes have one or more inputs and outputs. Input can be 'required' then node cannot run without this input received. Input and output can be dynamically declaration (as pattern or free). Output can have default value. Input and output sored their values. Input and output have a start counter. Nodes run after all required input received. Nodes run everytime when any input received if all required input has value. Nodes can be force running from eval() method (no recommended). Nodes can emit request and receive response.
The module provides a sume number of base nodes:
- Manager nodes: base thread controll
- Logical nodes: base logical operation
- Arithmetical nodes: base arithmetical operation
- String nodes: base string operation
- Array nodes: base array operation
- Other nodes: base value emitrs, debug, counters You also can declaration user node
Start node, executed when the process starts
- mixed value = true
┌─────────────┐
│ ├─ out1
│ │
│ │
│ ├─ out2
│ BeginNode │
│ │
│ ├─ ...
│ │
│ │
│ ├─ out$n
└─────────────┘
none
- one or more outputs by pattern out{number}
none
emit $value from all outputs
End node, collect result of process
none
┌───────────────┐
in1 ─┤ │
│ │
in2 ─┤ │
│ EndNode │
... ─┤ │
│ │
in$n ─┤ │
└───────────────┘
- some count of any value with any names
none
none
Collect all input value and map it to process result array. Input can haw any names, this names map to result array key.
Forked process trates
none
┌───────────────┐
│ ├─ out1
│ │
│ ├─ out2
in ─┤ SplitterNode │
│ ├─ ...
│ │
│ ├─ out$n
└───────────────┘
- in - required any type
- eny count of value with name like pattern: out{number}
none
emit input value to all outputs out1 = out2 = ... = out$n = in
singlify input signals
none
┌───────────────┐
in ─┤ │
│ SingleNode ├─ out
reset ─┤ │
└───────────────┘
- in - required any type
- reset - any value to reset input lock
- out - equal first of in
none
emit output signal only for first time input signal
Waiting emit signal for continue
none
┌───────────────┐
in ─┤ │
│ WaitingNode ├─ out
emit ─┤ │
└───────────────┘
- in - required any type
- reset - required bool
- out - equal in
none
emit outputs only if 'emit' signal = true
emit additional signals when input signal received
none
┌───────────────┐
│ ├─ before
│ │
in ─┤ TriggerNode ├─ out
│ │
│ ├─ after
└───────────────┘
- in - required any type
- before - true
- out - equal in
- after - true
none
emit 'before'=true output when input received, before output emitted emit 'out' = 'in' emit 'after'=true output when input received, after output emitted
iterate array for each 'emit' signal received
none
┌───────────────┐
array ─┤ ├─ out
│ │
emit ─┤ IterateNode ├─ complete
│ │
reset ─┤ ├─ count
└───────────────┘
- array - required array
- emit - required any type
- reset - reset control
- out - any type value (emit for each elements of 'array')
- complete - true (emit when array is end)
- count - count of 'array' elements (emit when 'array' signal received)
none
emit 'count' = count(array) signal when 'array' signal received emit 'out' = array[$n] for each 'emit' signal received emit 'complete' = true when 'array' is end
Stop current thread until a response is received
none
┌───────────────┐
│ │
in ─┤ PauseNode ├─ out
│ │
└───────────────┘
- in - required any type
- out - any type value equal 'in'
- 'pause': waiting eny response
Stop current thread until a response is received then forward input to output
Repeat 'in' sume time
$value - count of repeat time
┌───────────────┐
│ ├─ out
in ─┤ RepeatNode │
│ ├─ complete
└───────────────┘
- in - required any type
- out - any type value equal 'in'
- complete - true (emit when repeat end)
none
Forward input to output and repeat it '$value' time. Emit complete = true when repeat time is end
Run subprocess (another instance of Process) inside node
$subprocessScheme like process builder
┌─────────────────────┐
in1 ─┤ ├─ out1
│ │
in2 ─┤ ├─ out2
│ SubProcessNode │
... ─┤ ├─ ...
│ │
in$n ─┤ ├─ ount$n
└─────────────────────┘
Depending on the scheme Map inputs to scheme parameters
Depending on the scheme Map subprocess output to node output
Forward request from subprocess Forward response to subprocess
Run subprocess (instance of Process) inside SubProcessNode, Map inputs to subprocess scheme parameters and map output of subprocess to current output Forward subprocess request and response Emit all output when subprocess status is Process::STATUS_COMPLETE
Run sume fork of subprocess (another instance of Process) inside node
$subprocessScheme like process builder
┌─────────────────────┐
in1 ─┤ ├─ out1
│ │
in2 ─┤ ├─ out2
│ MultiSubProcessNode │
... ─┤ ├─ ...
│ │
in$n ─┤ ├─ ount$n
└─────────────────────┘
Depending on the scheme Map simple inputs to scheme parameters Map each element of array inputs to appropriate number of subprocess
Depending on the scheme Map collected subprocesses outputs (as array)
Forward request from subprocesses Forward response to subprocesses
Run subprocess instance for each array element of greatest input value Collect all subprocesses outputs as appropriate arrays and map it to output forward all subprocesses request to node request forward all node response to subprocesses response emit all output when all subprocesses status is Process::STATUS_COMPLETE
Logical AND node
none
┌───────────────┐
in1 ─┤ │
│ ├─ out
in2 ─┤ │
│ AndNode │
... ─┤ │
│ ├─ iout
in$n ─┤ │
└───────────────┘
- some inputs names like pattern 'in{$number}' - required boolean
- out - logical AND of all inputs
- iout - inverted out
none
'out' = 'in1' && 'in2' && ... && 'in$n' 'iout' = !'out'
Logical NOT node
none
┌───────────────┐
│ │
in ─┤ CountNode ├─ out
│ │
└───────────────┘
- in - required boolean
- out - logical NOT of input
none
'out' = !'in'
Logical OR node
none
┌───────────────┐
in1 ─┤ │
│ ├─ out
in2 ─┤ │
│ OrNode │
... ─┤ │
│ ├─ iout
in$n ─┤ │
└───────────────┘
- some inputs names like pattern 'in{$number}' - required boolean
- out - logical AND of all inputs
- iout - inverted out
none
'out' = 'in1' || 'in2' || ... || 'in$n'
Logical XOR node
none
┌───────────────┐
in1 ─┤ │
│ ├─ out
in2 ─┤ │
│ XorNode │
... ─┤ │
│ ├─ iout
in$n ─┤ │
└───────────────┘
- some inputs names like pattern 'in{$number}' - required boolean
- out - logical XOR of all inputs
- iout - inverted out
none
out = (in1 || in2 || .. || in$n) && !(in1 && in2) && !(in2 && in3) && !(in1 && in3) ..... only one value must be true iout = !out
Logical XOR node
none
┌───────────────┐
│ ├─ more
in1 ─┤ │
│ │
│ CompareNode ├─ less
│ │
in2 ─┤ │
│ ├─ equal
└───────────────┘
- in1 - required some compared value
- in2 - required some compared value
- more - true when in1 > in2
- less - true when in1 < in2
- equal - true when in1 == in2
none
more = in1 > in2 less = in1 < in2 equal = in1 == in2
Ariphmetic devide node
none
┌───────────────┐
in1 ─┤ │
│ │
in2 ─┤ │
│ DivideNode ├─ out
... ─┤ │
│ │
in$n ─┤ │
└───────────────┘
- some inputs names like pattern 'in{$number}' - required number
- out - divide in1 to all in$n inputs
none
out = in1 / in2 / .. / in$n
Ariphmetic mod node
none
┌───────────────┐
in1 ─┤ │
│ │
in2 ─┤ │
│ ModNode ├─ out
... ─┤ │
│ │
in$n ─┤ │
└───────────────┘
- some inputs names like pattern 'in{$number}' - required number
- out - mod of divide in1 to all in$n inputs
none
out = in1 % in2 % .. % in$n
Ariphmetic multiply node
none
┌──────────────┐
in1 ─┤ │
│ │
in2 ─┤ │
│ MultiplyNode ├─ out
... ─┤ │
│ │
in$n ─┤ │
└──────────────┘
- some inputs names like pattern 'in{$number}' - required number
- out - multiply all in$n inputs
none
out = in1 * in2 * .. * in$n
Ariphmetic substract node
none
┌───────────────┐
in1 ─┤ │
│ │
in2 ─┤ │
│ SubstractNode ├─ out
... ─┤ │
│ │
in$n ─┤ │
└───────────────┘
- some inputs names like pattern 'in{$number}' - required number
- out - substract in1 and all in$n inputs
none
out = in1 - in2 - .. - in$n
Ariphmetic sum node
none
┌───────────────┐
in1 ─┤ │
│ │
in2 ─┤ │
│ SumNode ├─ out
... ─┤ │
│ │
in$n ─┤ │
└───────────────┘
- some inputs names like pattern 'in{$number}' - required number
- out - sum of all inputs
none
out = in1 + in2 + .. + in$n
String concatination node
none
┌───────────────┐
in1 ─┤ │
│ │
in2 ─┤ │
│ ConcatNode ├─ out
... ─┤ │
│ │
in$n ─┤ │
└───────────────┘
- some inputs names like pattern 'in{$number}' - required string
- out - concatination of all inputs
none
'out' = in1 . in2 . ... . in$n
String match node
$pattern - regexp string for matching
┌───────────────┐
│ ├─ out
in ─┤ MatchNode │
│ ├─ iout
└───────────────┘
- in - required string
- out - true if match success
- iout - inverted out
none
Emit 'out' if 'in' match pattern Emit 'iout' if 'in' don't match pattern
Replace string or string part
$pattern - regexp string for matching $replacement - string for replace
┌───────────────┐
│ │
in ─┤ ReplaceNode ├─ out
│ │
└───────────────┘
- in - required string
- out - result string
none
equal preg_replace($pattern, $replacement, 'in');
Collect input signals to array
none
┌───────────────┐
in ─┤ │
│ CollectNode ├─ out
emit ─┤ │
└───────────────┘
- in - required mixed
- emit - required true
- out - array of input values
none
Collect all 'in' signals to array emit this array when 'emit' received
Collect all inputs to single array
none
┌───────────────┐
in1 ─┤ │
│ │
in2 ─┤ │
│ CombineNode ├─ out
... ─┤ │
│ │
in$n ─┤ │
└───────────────┘
- some inputs names like pattern 'in{$number}' - required mixed
- out - array of inputs values
none
Combine all inputs to array like ['in1' => $valueOfIn1, 'in2' => $valueOfIn2 , .....]
Collect input signals to array
none
┌───────────────┐
│ │
array ─┤ CountNode ├─ out
│ │
└───────────────┘
- array - required array
- out - count of array values
none
emit count of 'array' elements
Emit output for each element of input array
none
┌──────────────┐
│ ├─ out
│ │
array ─┤ EachNode ├─ key
│ │
│ ├─ complete
└──────────────┘
- array - required array
- out - single value of 'array'
- key - single key of 'arra'
- complete - true when array end
none
Emit 'out' and 'key' for each 'array' elements Emit 'complete' when array is end
Exctract single value from array by key
$key - key
┌───────────────┐
│ │
array ─┤ ExtractNode ├─ out
│ │
└───────────────┘
- array - required array
- out - emit single value of array
none
Emit array[$key]
Calculate count of input signals
none
┌───────────────┐
│ │
in ─┤ CounterNode ├─ out
│ │
└───────────────┘
- in - required mixed
- out - emit count of input signals
none
calculate input signal count emit 'out' everytime when 'in' received
Dump input values
none
┌───────────────┐
│ │
in ─┤ DumpNode ├─ out
│ │
└───────────────┘
- in - required mixed
- out - equal 'in'
none
forward input to output call dump('in') if dump function available call var_export if running in cli mode call var_dump if running in fpm mode
Random value emiter
$min - min value of random $max - max value of random
┌───────────────┐
│ │
emit ─┤ RandNode ├─ out
│ │
└───────────────┘
- emit - required mixed
- out - random number value
none
when 'emit' received emit random($min=0, $max=1) value to 'out'
Range generator
$start - start valut of range $end - end value of range $step - step of range
┌───────────────┐
│ │
emit ─┤ RageNode ├─ out
│ │
└───────────────┘
- emit - required mixed
- out - array
none
equal range($start, $end, $step=1) emit array when 'emit' received
value emiter
$value - emitted value
┌───────────────┐
│ │
emit ─┤ ValueNode ├─ out
│ │
└───────────────┘
- emit - required mixed
- out - value
none
emit value when 'out' received
To create user node type, create a class extended from NodeAbstract and define public eval() method
Input and output policy declarated in static propery $scheme
static propery $scheme = [
'input' => [ //input declaration
'optionalInput' => [ //optional input named as 'optionalInput'
],
'requiredInput' => [ //required input named as 'requiredInput'
'required' => true, //set 'required' => true to make input required
]
],
'user_input' => [ //dynamic input declarated
'pattern' => '~in\d+~', //pattern for available input names
'property' => [
'required' => true //also can be required
]
],
'output' => [ //output declaration
'outputWithDefaultData' => [ //output named as 'outputWithDefaultData'
'data' => 'default data' //define 'data' property to define default data
],
'outputWithoutDefaultData' => [ //output named as 'outputWithoutDefaultData'
]
],
'user_output' => [ //dynamic output declarated
], //if pattern property is null, all names available
]Output emited only when all required input received
You can get access to input and output as
$value = $this->input['inputName']['data']; //get value from 'inputName' input
$this->output['outputName']['data'] = $value; //set value to 'outputName' output (not emitted)To emit output print:
$this->emit('outputName');
//or you can set value and output:
$this->emit('ouputName', $sumeValue);You can emit request from node:
$this->sendRequest($data, $id=null); //if $id == null $id get automaticaly uniq identifierTo process response in node extend setResponse method
public function setResponse($id, $data)
{
....do somethind
}