Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 187 additions & 0 deletions CommonLogic/Debugger/Diagrams/Flow.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
<?php

namespace Exface\Core\CommonLogic\Debugger\Diagrams;
use exface\Core\Exceptions\InvalidArgumentException;
use exface\Core\Exceptions\UnexpectedValueException;
use exface\Core\Interfaces\Diagrams\FlowInterface;

// below you find an example of the syntax and the writing style when applying the methods that you find in this Flow.php. The example is a flowchart that can be generated in PowerUI
// $diagram->addNodeStart('Task input');
// $diagram->continue('Collect task data', 'suedlink.Trasse.Baufelduebergabe', FlowNode::STYLE_DATA)
// ->continue('Refresh all data', 'suedlink.Trasse.Baufelduebergabe', FlowNode::STYLE_DATA)
// ->addNodeEnd('Prefill data', 'suedlink.Trasse.Baufelduebergabe');
//
// $diagram->addNodeStart('Task prefill');
// $diagram->continue('Collect task data', 'No data', FlowNode::STYLE_DATA);

//core structure and functionality for any type of flowchart
//abstract -> common functionality that can be reused by any specific type of flowchart AND allows subclasses to implement their own specific rendering logic while still reusing the core flowchart

abstract class Flow implements FlowInterface
{
// holds all the nodes in the flowchart
protected $nodes = [];
// holds all the links between the nodes
protected $links = [];
// reference to the last node added
protected $lastNode = null;

/**
* Summary of addNodeStart
* @param mixed $nodeOrTitle
* @param mixed $stringOrStyle
* @return \Exface\Core\CommonLogic\Debugger\Diagrams\FlowNode
*/
public function addNodeStart($nodeOrTitle, $stringOrStyle = null): FlowNode
{
$node = $this->addNode($nodeOrTitle, $stringOrStyle);
$this->setNodeLast($node);
return $node;
}

/**
*
* @param string|FlowNode $nodeOrTitle
* @param string|object $linkTitleOrObject
* @throws \exface\Core\Exceptions\InvalidArgumentException
* @return \Exface\Core\CommonLogic\Debugger\Diagrams\Flow
*/
public function continue($nodeOrTitle, $linkTitleOrObject, $stringOrStyle = null): self
{
$toNode = $this->addNode($nodeOrTitle, $stringOrStyle);

if (null !== $fromNode = $this->getNodeLast()) {
$this->addLink($fromNode, $toNode, FlowLink::getTitleForAnything($linkTitleOrObject));
}
$this->setNodeLast($toNode);
return $this;
}

/**
* Summary of addNodeEnd
* @param mixed $nodeOrTitle
* @param mixed $linkTitleOrObject
* @param mixed $stringOrStyle
* @return \Exface\Core\CommonLogic\Debugger\Diagrams\Flow
*/
public function addNodeEnd($nodeOrTitle, $linkTitleOrObject, $stringOrStyle = null): self
{
$toNode = $this->addNode($nodeOrTitle, $stringOrStyle);

if (null !== $fromNode = $this->getNodeLast()) {
$this->addLink($fromNode, $toNode, FlowLink::getTitleForAnything($linkTitleOrObject));
}
$this->setNodeLast($toNode);
return $this;
}

protected function getNodeLast() : ?FlowNode
{
return $this->lastNode ?? ($this->nodes[array_key_first($this->nodes)] ?? null);
}

protected function setNodeLast(FlowNode $node): Flow
{
$this->lastNode = $node;
return $this;
}

/**
*
* @param \Exface\Core\CommonLogic\Debugger\Diagrams\FlowNode $from
* @param \Exface\Core\CommonLogic\Debugger\Diagrams\FlowNode $to
* @param string $title
* @return \Exface\Core\CommonLogic\Debugger\Diagrams\Flow
*/
public function addLink($from, $to, $titleOrObject): self
{
switch (true) {
case $from instanceof FlowNode:
$fromNode = $from;
break;
case is_string($from):
$fromNode = $this->findNode($from);
if ($fromNode === null) {
$valueDescription = ($from === '') ? '"blank"' : $from;
throw new UnexpectedValueException('The filled in value of ' . $valueDescription . ' is invalid. Please use one of the already assigned titles for nodes');
}
break;
default: throw new InvalidArgumentException('Cannot continue flowchart: expecting string or node instance, received ' . gettype($from));
}

switch (true) {
case $to instanceof FlowNode:
$toNode = $to;
break;
case is_string($to):
$toNode = $this->findNode($to);
if ($fromNode === null) {
$valueDescription = ($to === '') ? '"blank"' : $to;
throw new UnexpectedValueException('The filled in value of ' . $valueDescription . ' is invalid. Please use one of the already assigned titles for nodes');
}
break;
default: throw new InvalidArgumentException('Cannot continue flowchart: expecting string or node instance, received ' . gettype($to));
}
$link = new FlowLink($fromNode, $toNode, FlowLink::getTitleForAnything($titleOrObject));
$this->links[] = $link;
return $this;
}

/**
* Summary of addNode
* @param mixed $nodeOrTitle
* @param mixed $stringOrStyle
* @throws \exface\Core\Exceptions\InvalidArgumentException
* @return \Exface\Core\CommonLogic\Debugger\Diagrams\FlowNode
*/
public function addNode($nodeOrTitle, $stringOrStyle = null) : FlowNode
{
switch (true) {
case $nodeOrTitle instanceof FlowNode:
$toNode = $nodeOrTitle;
break;
case is_string($nodeOrTitle):
$toNode = new FlowNode($nodeOrTitle, $stringOrStyle);
break;
default:
throw new InvalidArgumentException('Cannot continue flowchart: expecting string or node instance, received ' . get_class($nodeOrTitle));
}
$this->nodes[] = $toNode;
return $toNode;
}

/**
*
* @param mixed $title
* @return FlowNode|null
*/
protected function findNode($title) : ?FlowNode
{
foreach ($this->nodes as $node) {
if ($node->getTitle() === $title) {
return $node;
}
}
return null;
}

abstract public function render() : string;

/**
* Summary of getNodes
* @return FlowNode[]
*/
public function getNodes() : array
{
return $this->nodes;
}

/**
*
* @return FlowLink[]
*/
public function getLinks() : array
{
return $this->links;
}
}
70 changes: 70 additions & 0 deletions CommonLogic/Debugger/Diagrams/FlowLink.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

namespace Exface\Core\CommonLogic\Debugger\Diagrams;
use exface\Core\Interfaces\DataSheets\DataSheetInterface;

// represents link between two nodes, references to the start and end nodes
class FlowLink
{
protected $from;
protected $to;
protected $title;

public function __construct(FlowNode $from, FlowNode $to, string $title)
{
$this->from = $from;
$this->to = $to;
$this->title = $title;
}

// returns starting node
public function getNodeFrom(): FlowNode
{
return $this->from;
}

// returns ending node
public function getNodeTo(): FlowNode
{
return $this->to;
}

// returns title of the link
public function getTitle(): string
{
return $this->title;
}

/**
*
* @param string|object $something
* @return string
*/
public static function getTitleForAnything($something) : string
{
$str = '';
switch (true) {
case $something instanceof DataSheetInterface:
$dataSheet = $something;
$obj = $dataSheet->getMetaObject()->getAliasWithNamespace();
$rows = $dataSheet->countRows();
$cols = $dataSheet->getColumns()->count();
$filters = $dataSheet->getFilters()->countConditions() + $dataSheet->getFilters()->countNestedGroups();
if (empty($rows) && empty($cols) && empty($filters)) {
return "\"{$obj}\nblank\"";
}
$str = "\"{$obj}\n{$rows} row(s), {$cols} col(s), {$filters} filter(s)\"";
break;
case is_string($something):
$str = $something;
break;
case $something instanceof \Stringable:
$str = $something->__toString();
break;
default:
$str = get_class($something);
break;
}
return $str;
}
}
43 changes: 43 additions & 0 deletions CommonLogic/Debugger/Diagrams/FlowLinkStyle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace Exface\Core\CommonLogic\Debugger\Diagrams;

// This class is not in use / applied - starting point for implementing e.g. dotted lines
// holds style properties how a link should be visually represented
class FlowLinkStyle
{
private $name; // name of style
private $color; // get color
private $arrow; // arrow type
private $weight; // weight or thickness of the link

public function __construct(string $name, string $stroke, string $arrow = null, string $weight)
{
$this->name = $name;
$this->stroke = $stroke;
$this->arrow = $arrow;
$this->weight = $weight;
}

// getter methods to retrieve the style properties
public function getName(): string
{
return $this->name;
}

public function getStroke(): string
{
return $this->color;
}

public function getArrow(): string
{
return $this->arrow;
}

public function getWeight(): string
{
return $this->weight;
}

}
62 changes: 62 additions & 0 deletions CommonLogic/Debugger/Diagrams/FlowNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

namespace Exface\Core\CommonLogic\Debugger\Diagrams;

class FlowNode
{
const STYLE_SQUARE = 'square';

const STYLE_ROUND = 'round';

const STYLE_PROCESS = 'process';

const STYLE_DATA = 'data';

const STYLE_ERROR = 'error';

protected $title; // Node title
protected $style; // Node style, instance of FlowChartNodeStyle

public function __construct(string $title = null, $style = null)
{
$this->title = $title;
$this->style = $style;
}

// returns title of node
public function getTitle(): string
{
return $this->title;
}

// returns style of node
public function getStyle(): ?FlowNodeStyle
{
if (is_string($this->style)) {
$this->style = $this->getStyleFromPreset($this->style);
}
return $this->style;
}

/**
* Summary of getStyleFromPreset
* @param string $preset
* @return FlowNodeStyle
*/
protected function getStyleFromPreset(string $preset): ?FlowNodeStyle
{
switch ($preset) {
case self::STYLE_SQUARE:
case self::STYLE_DATA:
$style = new FlowNodeStyle($preset, FlowNodeStyle::SHAPE_SQUARE);
break;
case self::STYLE_ROUND:
case self::STYLE_PROCESS:
$style = new FlowNodeStyle($preset, FlowNodeStyle::SHAPE_ROUND);
break;
case self::STYLE_ERROR:
$style = new FlowNodeStyle($preset, FlowNodeStyle::SHAPE_SQUARE, 'red');
}
return $style;
}
}
Loading