skrip42 / node-processor
Node processor
Requires
- php: ^7.1.3
This package is auto-updated.
Last update: 2024-10-28 21:19:55 UTC
README
Description
Node Process is a small procedural like program executable on top of php.
Installing
composer require skrip42/node-processor
Documentation
- ComonNodes
- Creating user node
Node Process
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.
Base usage
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;
Create process
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 policy
The 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
Running process and debug
For start process:
$result = $process->run(); // running process $state = $process->getState(); // you also can get current process state for debug you script
You 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
Serialize/deserialize process
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!
Process builder
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 ] );
Request/Response
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
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
ComonNodes
Manager nodes
BeginNode
Description:
Start node, executed when the process starts
Parametrs:
- mixed value = true
Grapical:
┌─────────────┐
│ ├─ out1
│ │
│ │
│ ├─ out2
│ BeginNode │
│ │
│ ├─ ...
│ │
│ │
│ ├─ out$n
└─────────────┘
Inputs:
none
Outputs:
- one or more outputs by pattern out{number}
Requests:
none
Logic:
emit $value from all outputs
EndNode
Description:
End node, collect result of process
Parametrs:
none
Grapical:
┌───────────────┐
in1 ─┤ │
│ │
in2 ─┤ │
│ EndNode │
... ─┤ │
│ │
in$n ─┤ │
└───────────────┘
Inputs:
- some count of any value with any names
Outputs:
none
Requests:
none
Logic:
Collect all input value and map it to process result array. Input can haw any names, this names map to result array key.
SplitterNode
Description:
Forked process trates
Parametrs:
none
Grapical:
┌───────────────┐
│ ├─ out1
│ │
│ ├─ out2
in ─┤ SplitterNode │
│ ├─ ...
│ │
│ ├─ out$n
└───────────────┘
Inputs:
- in - required any type
Outputs:
- eny count of value with name like pattern: out{number}
Requests:
none
Logic:
emit input value to all outputs out1 = out2 = ... = out$n = in
SingleNode
Description:
singlify input signals
Parametrs:
none
Grapical:
┌───────────────┐
in ─┤ │
│ SingleNode ├─ out
reset ─┤ │
└───────────────┘
Inputs:
- in - required any type
- reset - any value to reset input lock
Outputs:
- out - equal first of in
Requests:
none
Logic:
emit output signal only for first time input signal
WaitingNode
Description:
Waiting emit signal for continue
Parametrs:
none
Grapical:
┌───────────────┐
in ─┤ │
│ WaitingNode ├─ out
emit ─┤ │
└───────────────┘
Inputs:
- in - required any type
- reset - required bool
Outputs:
- out - equal in
Requests:
none
Logic:
emit outputs only if 'emit' signal = true
TriggerNode
Description:
emit additional signals when input signal received
Parametrs:
none
Grapical:
┌───────────────┐
│ ├─ before
│ │
in ─┤ TriggerNode ├─ out
│ │
│ ├─ after
└───────────────┘
Inputs:
- in - required any type
Outputs:
- before - true
- out - equal in
- after - true
Requests:
none
Logic:
emit 'before'=true output when input received, before output emitted emit 'out' = 'in' emit 'after'=true output when input received, after output emitted
IterateNode
Description:
iterate array for each 'emit' signal received
Parametrs:
none
Grapical:
┌───────────────┐
array ─┤ ├─ out
│ │
emit ─┤ IterateNode ├─ complete
│ │
reset ─┤ ├─ count
└───────────────┘
Inputs:
- array - required array
- emit - required any type
- reset - reset control
Outputs:
- 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)
Requests:
none
Logic:
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
PauseNode
Description:
Stop current thread until a response is received
Parametrs:
none
Grapical:
┌───────────────┐
│ │
in ─┤ PauseNode ├─ out
│ │
└───────────────┘
Inputs:
- in - required any type
Outputs:
- out - any type value equal 'in'
Requests:
- 'pause': waiting eny response
Logic:
Stop current thread until a response is received then forward input to output
RepeatNode
Description:
Repeat 'in' sume time
Parametrs:
$value - count of repeat time
Grapical:
┌───────────────┐
│ ├─ out
in ─┤ RepeatNode │
│ ├─ complete
└───────────────┘
Inputs:
- in - required any type
Outputs:
- out - any type value equal 'in'
- complete - true (emit when repeat end)
Requests:
none
Logic:
Forward input to output and repeat it '$value' time. Emit complete = true when repeat time is end
SubprocessNode
Description:
Run subprocess (another instance of Process) inside node
Parametrs:
$subprocessScheme like process builder
Grapical:
┌─────────────────────┐
in1 ─┤ ├─ out1
│ │
in2 ─┤ ├─ out2
│ SubProcessNode │
... ─┤ ├─ ...
│ │
in$n ─┤ ├─ ount$n
└─────────────────────┘
Inputs:
Depending on the scheme Map inputs to scheme parameters
Outputs:
Depending on the scheme Map subprocess output to node output
Requests:
Forward request from subprocess Forward response to subprocess
Logic:
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
MultiSubProcessNode
Description:
Run sume fork of subprocess (another instance of Process) inside node
Parametrs:
$subprocessScheme like process builder
Grapical:
┌─────────────────────┐
in1 ─┤ ├─ out1
│ │
in2 ─┤ ├─ out2
│ MultiSubProcessNode │
... ─┤ ├─ ...
│ │
in$n ─┤ ├─ ount$n
└─────────────────────┘
Inputs:
Depending on the scheme Map simple inputs to scheme parameters Map each element of array inputs to appropriate number of subprocess
Outputs:
Depending on the scheme Map collected subprocesses outputs (as array)
Requests:
Forward request from subprocesses Forward response to subprocesses
Logic:
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 nodes
AndNode
Description:
Logical AND node
Parametrs:
none
Grapical:
┌───────────────┐
in1 ─┤ │
│ ├─ out
in2 ─┤ │
│ AndNode │
... ─┤ │
│ ├─ iout
in$n ─┤ │
└───────────────┘
Inputs:
- some inputs names like pattern 'in{$number}' - required boolean
Outputs:
- out - logical AND of all inputs
- iout - inverted out
Requests:
none
Logic:
'out' = 'in1' && 'in2' && ... && 'in$n' 'iout' = !'out'
NotNode
Description:
Logical NOT node
Parametrs:
none
Grapical:
┌───────────────┐
│ │
in ─┤ CountNode ├─ out
│ │
└───────────────┘
Inputs:
- in - required boolean
Outputs:
- out - logical NOT of input
Requests:
none
Logic:
'out' = !'in'
OrNode
Description:
Logical OR node
Parametrs:
none
Grapical:
┌───────────────┐
in1 ─┤ │
│ ├─ out
in2 ─┤ │
│ OrNode │
... ─┤ │
│ ├─ iout
in$n ─┤ │
└───────────────┘
Inputs:
- some inputs names like pattern 'in{$number}' - required boolean
Outputs:
- out - logical AND of all inputs
- iout - inverted out
Requests:
none
Logic:
'out' = 'in1' || 'in2' || ... || 'in$n'
XorNode
Description:
Logical XOR node
Parametrs:
none
Grapical:
┌───────────────┐
in1 ─┤ │
│ ├─ out
in2 ─┤ │
│ XorNode │
... ─┤ │
│ ├─ iout
in$n ─┤ │
└───────────────┘
Inputs:
- some inputs names like pattern 'in{$number}' - required boolean
Outputs:
- out - logical XOR of all inputs
- iout - inverted out
Requests:
none
Logic:
out = (in1 || in2 || .. || in$n) && !(in1 && in2) && !(in2 && in3) && !(in1 && in3) ..... only one value must be true iout = !out
CompareNode
Description:
Logical XOR node
Parametrs:
none
Grapical:
┌───────────────┐
│ ├─ more
in1 ─┤ │
│ │
│ CompareNode ├─ less
│ │
in2 ─┤ │
│ ├─ equal
└───────────────┘
Inputs:
- in1 - required some compared value
- in2 - required some compared value
Outputs:
- more - true when in1 > in2
- less - true when in1 < in2
- equal - true when in1 == in2
Requests:
none
Logic:
more = in1 > in2 less = in1 < in2 equal = in1 == in2
Arithmetical nodes
DivideNode
Description:
Ariphmetic devide node
Parametrs:
none
Grapical:
┌───────────────┐
in1 ─┤ │
│ │
in2 ─┤ │
│ DivideNode ├─ out
... ─┤ │
│ │
in$n ─┤ │
└───────────────┘
Inputs:
- some inputs names like pattern 'in{$number}' - required number
Outputs:
- out - divide in1 to all in$n inputs
Requests:
none
Logic:
out = in1 / in2 / .. / in$n
ModNode
Description:
Ariphmetic mod node
Parametrs:
none
Grapical:
┌───────────────┐
in1 ─┤ │
│ │
in2 ─┤ │
│ ModNode ├─ out
... ─┤ │
│ │
in$n ─┤ │
└───────────────┘
Inputs:
- some inputs names like pattern 'in{$number}' - required number
Outputs:
- out - mod of divide in1 to all in$n inputs
Requests:
none
Logic:
out = in1 % in2 % .. % in$n
MultiptyNode
Description:
Ariphmetic multiply node
Parametrs:
none
Grapical:
┌──────────────┐
in1 ─┤ │
│ │
in2 ─┤ │
│ MultiplyNode ├─ out
... ─┤ │
│ │
in$n ─┤ │
└──────────────┘
Inputs:
- some inputs names like pattern 'in{$number}' - required number
Outputs:
- out - multiply all in$n inputs
Requests:
none
Logic:
out = in1 * in2 * .. * in$n
SubstractNode
Description:
Ariphmetic substract node
Parametrs:
none
Grapical:
┌───────────────┐
in1 ─┤ │
│ │
in2 ─┤ │
│ SubstractNode ├─ out
... ─┤ │
│ │
in$n ─┤ │
└───────────────┘
Inputs:
- some inputs names like pattern 'in{$number}' - required number
Outputs:
- out - substract in1 and all in$n inputs
Requests:
none
Logic:
out = in1 - in2 - .. - in$n
SumNode
Description:
Ariphmetic sum node
Parametrs:
none
Grapical:
┌───────────────┐
in1 ─┤ │
│ │
in2 ─┤ │
│ SumNode ├─ out
... ─┤ │
│ │
in$n ─┤ │
└───────────────┘
Inputs:
- some inputs names like pattern 'in{$number}' - required number
Outputs:
- out - sum of all inputs
Requests:
none
Logic:
out = in1 + in2 + .. + in$n
String nodes
ConcatNode
Description:
String concatination node
Parametrs:
none
Grapical:
┌───────────────┐
in1 ─┤ │
│ │
in2 ─┤ │
│ ConcatNode ├─ out
... ─┤ │
│ │
in$n ─┤ │
└───────────────┘
Inputs:
- some inputs names like pattern 'in{$number}' - required string
Outputs:
- out - concatination of all inputs
Requests:
none
Logic:
'out' = in1 . in2 . ... . in$n
MatchNode
Description:
String match node
Parametrs:
$pattern - regexp string for matching
Grapical:
┌───────────────┐
│ ├─ out
in ─┤ MatchNode │
│ ├─ iout
└───────────────┘
Inputs:
- in - required string
Outputs:
- out - true if match success
- iout - inverted out
Requests:
none
Logic:
Emit 'out' if 'in' match pattern Emit 'iout' if 'in' don't match pattern
ReplaceNode
Description:
Replace string or string part
Parametrs:
$pattern - regexp string for matching $replacement - string for replace
Grapical:
┌───────────────┐
│ │
in ─┤ ReplaceNode ├─ out
│ │
└───────────────┘
Inputs:
- in - required string
Outputs:
- out - result string
Requests:
none
Logic:
equal preg_replace($pattern, $replacement, 'in');
Array nodes
CollectNode
Description:
Collect input signals to array
Parametrs:
none
Grapical:
┌───────────────┐
in ─┤ │
│ CollectNode ├─ out
emit ─┤ │
└───────────────┘
Inputs:
- in - required mixed
- emit - required true
Outputs:
- out - array of input values
Requests:
none
Logic:
Collect all 'in' signals to array emit this array when 'emit' received
CombineNode
Description:
Collect all inputs to single array
Parametrs:
none
Grapical:
┌───────────────┐
in1 ─┤ │
│ │
in2 ─┤ │
│ CombineNode ├─ out
... ─┤ │
│ │
in$n ─┤ │
└───────────────┘
Inputs:
- some inputs names like pattern 'in{$number}' - required mixed
Outputs:
- out - array of inputs values
Requests:
none
Logic:
Combine all inputs to array like ['in1' => $valueOfIn1, 'in2' => $valueOfIn2 , .....]
CountNode
Description:
Collect input signals to array
Parametrs:
none
Grapical:
┌───────────────┐
│ │
array ─┤ CountNode ├─ out
│ │
└───────────────┘
Inputs:
- array - required array
Outputs:
- out - count of array values
Requests:
none
Logic:
emit count of 'array' elements
EachNode
Description:
Emit output for each element of input array
Parametrs:
none
Grapical:
┌──────────────┐
│ ├─ out
│ │
array ─┤ EachNode ├─ key
│ │
│ ├─ complete
└──────────────┘
Inputs:
- array - required array
Outputs:
- out - single value of 'array'
- key - single key of 'arra'
- complete - true when array end
Requests:
none
Logic:
Emit 'out' and 'key' for each 'array' elements Emit 'complete' when array is end
ExtractNode
Description:
Exctract single value from array by key
Parametrs:
$key - key
Grapical:
┌───────────────┐
│ │
array ─┤ ExtractNode ├─ out
│ │
└───────────────┘
Inputs:
- array - required array
Outputs:
- out - emit single value of array
Requests:
none
Logic:
Emit array[$key]
Other nodes
CounterNode
Description:
Calculate count of input signals
Parametrs:
none
Grapical:
┌───────────────┐
│ │
in ─┤ CounterNode ├─ out
│ │
└───────────────┘
Inputs:
- in - required mixed
Outputs:
- out - emit count of input signals
Requests:
none
Logic:
calculate input signal count emit 'out' everytime when 'in' received
DumpNode
Description:
Dump input values
Parametrs:
none
Grapical:
┌───────────────┐
│ │
in ─┤ DumpNode ├─ out
│ │
└───────────────┘
Inputs:
- in - required mixed
Outputs:
- out - equal 'in'
Requests:
none
Logic:
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
RandNode
Description:
Random value emiter
Parametrs:
$min - min value of random $max - max value of random
Grapical:
┌───────────────┐
│ │
emit ─┤ RandNode ├─ out
│ │
└───────────────┘
Inputs:
- emit - required mixed
Outputs:
- out - random number value
Requests:
none
Logic:
when 'emit' received emit random($min=0, $max=1) value to 'out'
RangeNode
Description:
Range generator
Parametrs:
$start - start valut of range $end - end value of range $step - step of range
Grapical:
┌───────────────┐
│ │
emit ─┤ RageNode ├─ out
│ │
└───────────────┘
Inputs:
- emit - required mixed
Outputs:
- out - array
Requests:
none
Logic:
equal range($start, $end, $step=1) emit array when 'emit' received
ValueNode
Description:
value emiter
Parametrs:
$value - emitted value
Grapical:
┌───────────────┐
│ │
emit ─┤ ValueNode ├─ out
│ │
└───────────────┘
Inputs:
- emit - required mixed
Outputs:
- out - value
Requests:
none
Logic:
emit value when 'out' received
Creating user node
To create user node type, create a class extended from NodeAbstract and define public eval() method
Input/output defenition
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
Read input/output, emit signals
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);
Request/response processing
You can emit request from node:
$this->sendRequest($data, $id=null); //if $id == null $id get automaticaly uniq identifier
To process response in node extend setResponse method
public function setResponse($id, $data) { ....do somethind }