From e298225f414d7c352953c966406e925cf01ab1c6 Mon Sep 17 00:00:00 2001 From: Benjamin Peters Date: Thu, 29 Aug 2024 14:10:56 +0200 Subject: [PATCH 1/7] DEV FlowChart classes --- .../Debugger/Diagrams/ExtendFlowChart.php | 12 +++ CommonLogic/Debugger/Diagrams/FlowChart.php | 73 +++++++++++++++++++ .../Debugger/Diagrams/FlowChartLink.php | 46 ++++++++++++ .../Debugger/Diagrams/FlowChartLinkStyle.php | 41 +++++++++++ .../Debugger/Diagrams/FlowChartNode.php | 28 +++++++ .../Debugger/Diagrams/FlowChartNodeStyle.php | 36 +++++++++ .../Debugger/Diagrams/MermaidFlowChart.php | 33 +++++++++ .../Diagrams/MermaidFlowChartCustom.php | 44 +++++++++++ Interfaces/Diagrams/FlowChartInterface.php | 9 +++ 9 files changed, 322 insertions(+) create mode 100644 CommonLogic/Debugger/Diagrams/ExtendFlowChart.php create mode 100644 CommonLogic/Debugger/Diagrams/FlowChart.php create mode 100644 CommonLogic/Debugger/Diagrams/FlowChartLink.php create mode 100644 CommonLogic/Debugger/Diagrams/FlowChartLinkStyle.php create mode 100644 CommonLogic/Debugger/Diagrams/FlowChartNode.php create mode 100644 CommonLogic/Debugger/Diagrams/FlowChartNodeStyle.php create mode 100644 CommonLogic/Debugger/Diagrams/MermaidFlowChart.php create mode 100644 CommonLogic/Debugger/Diagrams/MermaidFlowChartCustom.php create mode 100644 Interfaces/Diagrams/FlowChartInterface.php diff --git a/CommonLogic/Debugger/Diagrams/ExtendFlowChart.php b/CommonLogic/Debugger/Diagrams/ExtendFlowChart.php new file mode 100644 index 000000000..2475dfc6b --- /dev/null +++ b/CommonLogic/Debugger/Diagrams/ExtendFlowChart.php @@ -0,0 +1,12 @@ + 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 FlowChart implements FlowChartInterface +{ + // 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; + + public function startNode(string $title, FlowChartNodeStyle $nodeStyle): FlowChartNode + { + $node = new FlowChartNode($title, $nodeStyle); + $this->nodes[] = $node; + $this->lastNode = $node; + return $node; // ultimately returns a newly created 'Node' object + } + + public function continue(string $toTitle, string $linkTitle, FlowChartNodeStyle $nodeStyle): self + { + $toNode = new FlowChartNode($toTitle, $nodeStyle); + $this->nodes[] = $toNode; + + if ($this->lastNode !== null) { + $this->addLink($this->lastNode, $toNode, $linkTitle, $nodeStyle); + } + $this->lastNode = $toNode; + return $this; + } + + protected function addLink(FlowChartNode $from, FlowChartNode $to, string $title, FlowChartNodeStyle $nodeStyle): self + { + $link = new FlowChartLink($from, $to, $title, $nodeStyle); + $this->links[] = $link; + return $this; + } + + public function endNode(string $toTitle, string $linkTitle, FlowChartNodeStyle $nodeStyle): void + { + $toNode = new FlowChartNode($toTitle, $nodeStyle); + $this->nodes[] = $toNode; + if ($this->lastNode !== null) { + $this->addLink($this->lastNode, $toNode, $linkTitle, $nodeStyle); + } + $this->lastNode = $toNode; + } + + // rendering of the complete diagram is done by other subclasses such as MermaidFlowChartCustom + abstract public function render() : string; + + /** + * Summary of getNodes + * @return FlowChartNode[] + */ + public function getNodes() : array + { + return $this->nodes; + } + + /** + * + * @return FlowChartLink[] + */ + public function getLinks() : array + { + return $this->links; + } +} \ No newline at end of file diff --git a/CommonLogic/Debugger/Diagrams/FlowChartLink.php b/CommonLogic/Debugger/Diagrams/FlowChartLink.php new file mode 100644 index 000000000..e2b3b9c50 --- /dev/null +++ b/CommonLogic/Debugger/Diagrams/FlowChartLink.php @@ -0,0 +1,46 @@ +from = $from; + $this->to = $to; + $this->title = $title; + } + + // returns starting node + public function getNodeFrom(): FlowChartNode + { + return $this->from; + } + + // returns ending node + public function getNodeTo(): FlowChartNode + { + return $this->to; + } + + // returns title of the link + public function getTitle(): string + { + return $this->title; + } + + // returns style associated with the link + public function getStyle(): FlowChartLinkStyle + { + return $this->style; + } +} diff --git a/CommonLogic/Debugger/Diagrams/FlowChartLinkStyle.php b/CommonLogic/Debugger/Diagrams/FlowChartLinkStyle.php new file mode 100644 index 000000000..9684d768d --- /dev/null +++ b/CommonLogic/Debugger/Diagrams/FlowChartLinkStyle.php @@ -0,0 +1,41 @@ +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->stroke; + } + + public function getArrow(): string + { + return $this->arrow; + } + + public function getWeight(): string + { + return $this->weight; + } +} diff --git a/CommonLogic/Debugger/Diagrams/FlowChartNode.php b/CommonLogic/Debugger/Diagrams/FlowChartNode.php new file mode 100644 index 000000000..536833227 --- /dev/null +++ b/CommonLogic/Debugger/Diagrams/FlowChartNode.php @@ -0,0 +1,28 @@ +title = $title; + $this->style = $style; + } + + // returns title of node + public function getTitle(): string + { + return $this->title; + } + + // returns style of node + public function getStyle(): FlowChartNodeStyle + { + return $this->style; + } +} diff --git a/CommonLogic/Debugger/Diagrams/FlowChartNodeStyle.php b/CommonLogic/Debugger/Diagrams/FlowChartNodeStyle.php new file mode 100644 index 000000000..24ba99f0a --- /dev/null +++ b/CommonLogic/Debugger/Diagrams/FlowChartNodeStyle.php @@ -0,0 +1,36 @@ +name = $name; + $this->shape = $shape; + $this->color = $color; + } + + // getter methods to retrieve the style properties + public function getName(): string + { + return $this->name; + } + + public function getShape(): string + { + return $this->shape; + } + + public function getColor(): string + { + return $this->color; + } +} diff --git a/CommonLogic/Debugger/Diagrams/MermaidFlowChart.php b/CommonLogic/Debugger/Diagrams/MermaidFlowChart.php new file mode 100644 index 000000000..480452e94 --- /dev/null +++ b/CommonLogic/Debugger/Diagrams/MermaidFlowChart.php @@ -0,0 +1,33 @@ +getLinks() as $link) { + // getNodeId: generates a valid Mermaid.js ID for each node + $graphNode1 = new Node($graph, $this->getNodeId($link->getNodeFrom())); + $graphNode2 = new Node($graph, $this->getNodeId($link->getNodeTo())); + $graph->addNode($graphNode1); + $graph->addNode($graphNode2); + $graphLink = new Link($graphNode1, $graphNode2, $link->getTitle()); + $graph->addLink($graphLink); + } + return $graph->render(); + } + + protected function getNodeId(FlowChartNode $node) :string + { + return str_replace(' ', '_', $node->getTitle()); + } +} \ No newline at end of file diff --git a/CommonLogic/Debugger/Diagrams/MermaidFlowChartCustom.php b/CommonLogic/Debugger/Diagrams/MermaidFlowChartCustom.php new file mode 100644 index 000000000..b2a72d4d4 --- /dev/null +++ b/CommonLogic/Debugger/Diagrams/MermaidFlowChartCustom.php @@ -0,0 +1,44 @@ +nodes as $node) { + $output .= $this->renderNode($node) . "\n"; + } + foreach ($this->links as $link) { + $output .= $this->renderLink($link) . "\n"; + } + return $output; + } + + // converting a node into a Mermaid.js formatted string + public function renderNode(FlowChartNode $node) : string + { + return "{$this->getNodeId($node)}[{$this->escapeTitle($node->getTitle())}]"; + } + + public function renderLink(FlowChartLink $link) : string + { + // TODO find a new way to display style settings such as dotted etc. + $arrowType = ($link->style->name === "dotted") ?"-.->":"-->"; + return "{$link->getNodeFrom()->getTitle()} {$arrowType}|{$link->getTitle()}| {$link->getNodeTo()->getTitle()}"; + } + + // generates a valid ID for each node + protected function getNodeId(FlowChartNode $node) :string + { + return str_replace(' ', '_', $node->getTitle()); + } + + // special characters in node titles are properly escaped + protected function escapeTitle(string $title) : string + { + return addslashes($title); + } +} \ No newline at end of file diff --git a/Interfaces/Diagrams/FlowChartInterface.php b/Interfaces/Diagrams/FlowChartInterface.php new file mode 100644 index 000000000..ac442e76b --- /dev/null +++ b/Interfaces/Diagrams/FlowChartInterface.php @@ -0,0 +1,9 @@ + Date: Thu, 29 Aug 2024 16:03:37 +0200 Subject: [PATCH 2/7] FIX changing FlowChart classes, trying to make $nodestyle work --- CommonLogic/Debugger/Diagrams/FlowChart.php | 6 +++--- CommonLogic/Debugger/Diagrams/FlowChartLink.php | 4 ++-- CommonLogic/Debugger/Diagrams/MermaidFlowChart.php | 2 +- Interfaces/Diagrams/FlowChartInterface.php | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CommonLogic/Debugger/Diagrams/FlowChart.php b/CommonLogic/Debugger/Diagrams/FlowChart.php index 1c2b46778..1986b928d 100644 --- a/CommonLogic/Debugger/Diagrams/FlowChart.php +++ b/CommonLogic/Debugger/Diagrams/FlowChart.php @@ -1,7 +1,7 @@ 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 FlowChart implements FlowChartInterface @@ -33,9 +33,9 @@ public function continue(string $toTitle, string $linkTitle, FlowChartNodeStyle return $this; } - protected function addLink(FlowChartNode $from, FlowChartNode $to, string $title, FlowChartNodeStyle $nodeStyle): self + protected function addLink(FlowChartNode $from, FlowChartNode $to, string $title, FlowChartNodeStyle $style): self { - $link = new FlowChartLink($from, $to, $title, $nodeStyle); + $link = new FlowChartLink($from, $to, $title, $style); $this->links[] = $link; return $this; } diff --git a/CommonLogic/Debugger/Diagrams/FlowChartLink.php b/CommonLogic/Debugger/Diagrams/FlowChartLink.php index e2b3b9c50..66d20e01d 100644 --- a/CommonLogic/Debugger/Diagrams/FlowChartLink.php +++ b/CommonLogic/Debugger/Diagrams/FlowChartLink.php @@ -8,16 +8,16 @@ class FlowChartLink protected $from; protected $to; protected $title; - // public provides flexibility, allowing the style to be adjusted dynamically public $style; // Link style, instance of FlowChartLinkStyle // TODO continue: public function __construct(FlowChartNode $from, FlowChartNode $to, string $title, FlowChartLinkStyle $style) - public function __construct(FlowChartNode $from, FlowChartNode $to, string $title) + public function __construct(FlowChartNode $from, FlowChartNode $to, string $title, FlowChartLinkStyle $style) { $this->from = $from; $this->to = $to; $this->title = $title; + $this->style = $style; } // returns starting node diff --git a/CommonLogic/Debugger/Diagrams/MermaidFlowChart.php b/CommonLogic/Debugger/Diagrams/MermaidFlowChart.php index 480452e94..494b49a28 100644 --- a/CommonLogic/Debugger/Diagrams/MermaidFlowChart.php +++ b/CommonLogic/Debugger/Diagrams/MermaidFlowChart.php @@ -1,7 +1,7 @@ Date: Fri, 30 Aug 2024 07:54:05 +0200 Subject: [PATCH 3/7] FIX making changes on MermaidFlowChart.php because of incompabilities --- CommonLogic/Debugger/Diagrams/FlowChart.php | 20 +++++++------- .../Debugger/Diagrams/FlowChartLink.php | 11 +------- .../Debugger/Diagrams/FlowChartNode.php | 3 +-- .../Debugger/Diagrams/MermaidFlowChart.php | 27 ++++++++++++------- Interfaces/Diagrams/FlowChartInterface.php | 2 ++ 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/CommonLogic/Debugger/Diagrams/FlowChart.php b/CommonLogic/Debugger/Diagrams/FlowChart.php index 1986b928d..807022452 100644 --- a/CommonLogic/Debugger/Diagrams/FlowChart.php +++ b/CommonLogic/Debugger/Diagrams/FlowChart.php @@ -13,39 +13,39 @@ abstract class FlowChart implements FlowChartInterface // reference to the last node added protected $lastNode = null; - public function startNode(string $title, FlowChartNodeStyle $nodeStyle): FlowChartNode + public function startNode(string $title): FlowChartNode { - $node = new FlowChartNode($title, $nodeStyle); + $node = new FlowChartNode($title); $this->nodes[] = $node; $this->lastNode = $node; return $node; // ultimately returns a newly created 'Node' object } - public function continue(string $toTitle, string $linkTitle, FlowChartNodeStyle $nodeStyle): self + public function continue(string $toTitle, string $linkTitle): self { - $toNode = new FlowChartNode($toTitle, $nodeStyle); + $toNode = new FlowChartNode($toTitle); $this->nodes[] = $toNode; if ($this->lastNode !== null) { - $this->addLink($this->lastNode, $toNode, $linkTitle, $nodeStyle); + $this->addLink($this->lastNode, $toNode, $linkTitle); } $this->lastNode = $toNode; return $this; } - protected function addLink(FlowChartNode $from, FlowChartNode $to, string $title, FlowChartNodeStyle $style): self + protected function addLink(FlowChartNode $from, FlowChartNode $to, string $title): self { - $link = new FlowChartLink($from, $to, $title, $style); + $link = new FlowChartLink($from, $to, $title); $this->links[] = $link; return $this; } - public function endNode(string $toTitle, string $linkTitle, FlowChartNodeStyle $nodeStyle): void + public function endNode(string $toTitle, string $linkTitle): void { - $toNode = new FlowChartNode($toTitle, $nodeStyle); + $toNode = new FlowChartNode($toTitle); $this->nodes[] = $toNode; if ($this->lastNode !== null) { - $this->addLink($this->lastNode, $toNode, $linkTitle, $nodeStyle); + $this->addLink($this->lastNode, $toNode, $linkTitle); } $this->lastNode = $toNode; } diff --git a/CommonLogic/Debugger/Diagrams/FlowChartLink.php b/CommonLogic/Debugger/Diagrams/FlowChartLink.php index 66d20e01d..fddba9dc7 100644 --- a/CommonLogic/Debugger/Diagrams/FlowChartLink.php +++ b/CommonLogic/Debugger/Diagrams/FlowChartLink.php @@ -8,16 +8,13 @@ class FlowChartLink protected $from; protected $to; protected $title; - // public provides flexibility, allowing the style to be adjusted dynamically - public $style; // Link style, instance of FlowChartLinkStyle // TODO continue: public function __construct(FlowChartNode $from, FlowChartNode $to, string $title, FlowChartLinkStyle $style) - public function __construct(FlowChartNode $from, FlowChartNode $to, string $title, FlowChartLinkStyle $style) + public function __construct(FlowChartNode $from, FlowChartNode $to, string $title) { $this->from = $from; $this->to = $to; $this->title = $title; - $this->style = $style; } // returns starting node @@ -37,10 +34,4 @@ public function getTitle(): string { return $this->title; } - - // returns style associated with the link - public function getStyle(): FlowChartLinkStyle - { - return $this->style; - } } diff --git a/CommonLogic/Debugger/Diagrams/FlowChartNode.php b/CommonLogic/Debugger/Diagrams/FlowChartNode.php index 536833227..577b0b061 100644 --- a/CommonLogic/Debugger/Diagrams/FlowChartNode.php +++ b/CommonLogic/Debugger/Diagrams/FlowChartNode.php @@ -8,10 +8,9 @@ class FlowChartNode protected $title; // Node title protected $style; // Node style, instance of FlowChartNodeStyle - public function __construct(string $title, FlowChartNodeStyle $style) + public function __construct(string $title) { $this->title = $title; - $this->style = $style; } // returns title of node diff --git a/CommonLogic/Debugger/Diagrams/MermaidFlowChart.php b/CommonLogic/Debugger/Diagrams/MermaidFlowChart.php index 494b49a28..0d69d1f93 100644 --- a/CommonLogic/Debugger/Diagrams/MermaidFlowChart.php +++ b/CommonLogic/Debugger/Diagrams/MermaidFlowChart.php @@ -14,16 +14,23 @@ public function render(FlowChartInterface $flowChart) : string { $graph = new Graph(); - foreach ($flowChart->getLinks() as $link) { - // getNodeId: generates a valid Mermaid.js ID for each node - $graphNode1 = new Node($graph, $this->getNodeId($link->getNodeFrom())); - $graphNode2 = new Node($graph, $this->getNodeId($link->getNodeTo())); - $graph->addNode($graphNode1); - $graph->addNode($graphNode2); - $graphLink = new Link($graphNode1, $graphNode2, $link->getTitle()); - $graph->addLink($graphLink); - } - return $graph->render(); + // Ensure we add all nodes to the graph first + $nodeMap = []; + foreach ($flowChart->getNodes() as $node) { + $nodeId = $this->getNodeId($node); + $graphNode = new Node($graph, $nodeId); + $graphNode->setText($node->getTitle()); + $nodeMap[$nodeId] = $graphNode; + $graph->addNode($graphNode); + } + + // Then add all links between nodes + foreach ($flowChart->getLinks() as $link) { + $fromNode = $nodeMap[$this->getNodeId($link->getNodeFrom())]; + $toNode = $nodeMap[$this->getNodeId($link->getNodeTo())]; + $graphLink = new Link($fromNode, $toNode, $link->getTitle()); + $graph->addLink($graphLink); + } } protected function getNodeId(FlowChartNode $node) :string diff --git a/Interfaces/Diagrams/FlowChartInterface.php b/Interfaces/Diagrams/FlowChartInterface.php index af44f9c4b..23848dc02 100644 --- a/Interfaces/Diagrams/FlowChartInterface.php +++ b/Interfaces/Diagrams/FlowChartInterface.php @@ -6,4 +6,6 @@ interface FlowChartInterface { public function getLinks(): array; + + public function getNodes(): array; } From 261c2d30f8b38c29d6280c21cb1f0bc727cb34b6 Mon Sep 17 00:00:00 2001 From: Benjamin Peters Date: Mon, 2 Sep 2024 14:41:51 +0200 Subject: [PATCH 4/7] FIX making changes in MermaidFlowChart.php, diagram visible in the browser --- CommonLogic/Debugger/Diagrams/FlowChart.php | 11 + .../Debugger/Diagrams/MermaidFlowChart.php | 29 +- vendor/autoload.php | 25 + vendor/composer/ClassLoader.php | 579 ++++++++++++++++++ vendor/composer/LICENSE | 21 + vendor/composer/autoload_classmap.php | 10 + vendor/composer/autoload_namespaces.php | 9 + vendor/composer/autoload_psr4.php | 10 + vendor/composer/autoload_real.php | 38 ++ vendor/composer/autoload_static.php | 36 ++ vendor/composer/platform_check.php | 26 + 11 files changed, 776 insertions(+), 18 deletions(-) create mode 100644 vendor/autoload.php create mode 100644 vendor/composer/ClassLoader.php create mode 100644 vendor/composer/LICENSE create mode 100644 vendor/composer/autoload_classmap.php create mode 100644 vendor/composer/autoload_namespaces.php create mode 100644 vendor/composer/autoload_psr4.php create mode 100644 vendor/composer/autoload_real.php create mode 100644 vendor/composer/autoload_static.php create mode 100644 vendor/composer/platform_check.php diff --git a/CommonLogic/Debugger/Diagrams/FlowChart.php b/CommonLogic/Debugger/Diagrams/FlowChart.php index 807022452..33189e7ed 100644 --- a/CommonLogic/Debugger/Diagrams/FlowChart.php +++ b/CommonLogic/Debugger/Diagrams/FlowChart.php @@ -20,6 +20,17 @@ public function startNode(string $title): FlowChartNode $this->lastNode = $node; return $node; // ultimately returns a newly created 'Node' object } + + /* + // Possible method to consider in case of adding a Node such as 'Task prefill' + + public function addNode(string $title): FlowChartNode + { + $node = new FlowChartNode($title); + $this->nodes[] = $node; + $this->lastNode = $node; + return $node; + } */ public function continue(string $toTitle, string $linkTitle): self { diff --git a/CommonLogic/Debugger/Diagrams/MermaidFlowChart.php b/CommonLogic/Debugger/Diagrams/MermaidFlowChart.php index 0d69d1f93..aa7d5daa7 100644 --- a/CommonLogic/Debugger/Diagrams/MermaidFlowChart.php +++ b/CommonLogic/Debugger/Diagrams/MermaidFlowChart.php @@ -12,25 +12,18 @@ class MermaidFlowChart // takes the FlowChartInterface object and converts nodes and links into Mermaid.js public function render(FlowChartInterface $flowChart) : string { - $graph = new Graph(); + $graph = new Graph(['direction' => Graph::LEFT_RIGHT]); - // Ensure we add all nodes to the graph first - $nodeMap = []; - foreach ($flowChart->getNodes() as $node) { - $nodeId = $this->getNodeId($node); - $graphNode = new Node($graph, $nodeId); - $graphNode->setText($node->getTitle()); - $nodeMap[$nodeId] = $graphNode; - $graph->addNode($graphNode); - } - - // Then add all links between nodes - foreach ($flowChart->getLinks() as $link) { - $fromNode = $nodeMap[$this->getNodeId($link->getNodeFrom())]; - $toNode = $nodeMap[$this->getNodeId($link->getNodeTo())]; - $graphLink = new Link($fromNode, $toNode, $link->getTitle()); - $graph->addLink($graphLink); - } + foreach ($flowChart->getLinks() as $link) { + // getNodeId: generates a valid Mermaid.js ID for each node + $nodeFromId = new Node($this->getNodeId($link->getNodeFrom()), $link->getNodeFrom()->getTitle()); + $nodeToId = new Node($this->getNodeId($link->getNodeTo()), $link->getNodeTo()->getTitle()); + $graph->addNode($nodeFromId); + $graph->addNode($nodeToId); + $graphLink = new Link($nodeFromId, $nodeToId, $link->getTitle()); + $graph->addLink($graphLink); + } + return $graph->render(); } protected function getNodeId(FlowChartNode $node) :string diff --git a/vendor/autoload.php b/vendor/autoload.php new file mode 100644 index 000000000..576c982d4 --- /dev/null +++ b/vendor/autoload.php @@ -0,0 +1,25 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + /** @var \Closure(string):void */ + private static $includeFile; + + /** @var string|null */ + private $vendorDir; + + // PSR-4 + /** + * @var array> + */ + private $prefixLengthsPsr4 = array(); + /** + * @var array> + */ + private $prefixDirsPsr4 = array(); + /** + * @var list + */ + private $fallbackDirsPsr4 = array(); + + // PSR-0 + /** + * List of PSR-0 prefixes + * + * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) + * + * @var array>> + */ + private $prefixesPsr0 = array(); + /** + * @var list + */ + private $fallbackDirsPsr0 = array(); + + /** @var bool */ + private $useIncludePath = false; + + /** + * @var array + */ + private $classMap = array(); + + /** @var bool */ + private $classMapAuthoritative = false; + + /** + * @var array + */ + private $missingClasses = array(); + + /** @var string|null */ + private $apcuPrefix; + + /** + * @var array + */ + private static $registeredLoaders = array(); + + /** + * @param string|null $vendorDir + */ + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + self::initializeIncludeClosure(); + } + + /** + * @return array> + */ + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + /** + * @return array> + */ + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + /** + * @return list + */ + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + /** + * @return list + */ + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + /** + * @return array Array of classname => path + */ + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + * + * @return void + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void + */ + public function add($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 base directories + * + * @return void + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + * + * @return void + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + * + * @return void + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + * + * @return void + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + * + * @return void + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + $includeFile = self::$includeFile; + $includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders keyed by their corresponding vendor directories. + * + * @return array + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + /** + * @param string $class + * @param string $ext + * @return string|false + */ + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } + + /** + * @return void + */ + private static function initializeIncludeClosure() + { + if (self::$includeFile !== null) { + return; + } + + /** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + */ + self::$includeFile = \Closure::bind(static function($file) { + include $file; + }, null, null); + } +} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE new file mode 100644 index 000000000..f27399a04 --- /dev/null +++ b/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php new file mode 100644 index 000000000..0fb0a2c19 --- /dev/null +++ b/vendor/composer/autoload_classmap.php @@ -0,0 +1,10 @@ + $vendorDir . '/composer/InstalledVersions.php', +); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php new file mode 100644 index 000000000..15a2ff3ad --- /dev/null +++ b/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($baseDir . '/'), +); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php new file mode 100644 index 000000000..cd828ab57 --- /dev/null +++ b/vendor/composer/autoload_real.php @@ -0,0 +1,38 @@ +register(true); + + return $loader; + } +} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php new file mode 100644 index 000000000..27210e700 --- /dev/null +++ b/vendor/composer/autoload_static.php @@ -0,0 +1,36 @@ + + array ( + 'exface\\Core\\' => 12, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'exface\\Core\\' => + array ( + 0 => __DIR__ . '/../..' . '/', + ), + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInite583d99b03ad449d5bb77b52da0c75ea::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInite583d99b03ad449d5bb77b52da0c75ea::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInite583d99b03ad449d5bb77b52da0c75ea::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php new file mode 100644 index 000000000..589e9e770 --- /dev/null +++ b/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 70200)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} From cc9849781a83149c008b16dcb938d8acbdd9f746 Mon Sep 17 00:00:00 2001 From: Benjamin Peters Date: Fri, 6 Sep 2024 11:42:53 +0200 Subject: [PATCH 5/7] FIX making fundamental changes to get the diagram properly working --- .../Debugger/Diagrams/ExtendFlowChart.php | 12 -- CommonLogic/Debugger/Diagrams/Flow.php | 146 ++++++++++++++++++ CommonLogic/Debugger/Diagrams/FlowChart.php | 84 ---------- .../Debugger/Diagrams/FlowChartLink.php | 37 ----- .../Debugger/Diagrams/FlowChartNode.php | 27 ---- CommonLogic/Debugger/Diagrams/FlowLink.php | 70 +++++++++ ...owChartLinkStyle.php => FlowLinkStyle.php} | 12 +- CommonLogic/Debugger/Diagrams/FlowNode.php | 58 +++++++ ...owChartNodeStyle.php => FlowNodeStyle.php} | 14 +- CommonLogic/Debugger/Diagrams/MermaidFlow.php | 70 +++++++++ .../Debugger/Diagrams/MermaidFlowChart.php | 33 ---- .../Diagrams/MermaidFlowChartCustom.php | 44 ------ ...owChartInterface.php => FlowInterface.php} | 2 +- 13 files changed, 360 insertions(+), 249 deletions(-) delete mode 100644 CommonLogic/Debugger/Diagrams/ExtendFlowChart.php create mode 100644 CommonLogic/Debugger/Diagrams/Flow.php delete mode 100644 CommonLogic/Debugger/Diagrams/FlowChart.php delete mode 100644 CommonLogic/Debugger/Diagrams/FlowChartLink.php delete mode 100644 CommonLogic/Debugger/Diagrams/FlowChartNode.php create mode 100644 CommonLogic/Debugger/Diagrams/FlowLink.php rename CommonLogic/Debugger/Diagrams/{FlowChartLinkStyle.php => FlowLinkStyle.php} (79%) create mode 100644 CommonLogic/Debugger/Diagrams/FlowNode.php rename CommonLogic/Debugger/Diagrams/{FlowChartNodeStyle.php => FlowNodeStyle.php} (62%) create mode 100644 CommonLogic/Debugger/Diagrams/MermaidFlow.php delete mode 100644 CommonLogic/Debugger/Diagrams/MermaidFlowChart.php delete mode 100644 CommonLogic/Debugger/Diagrams/MermaidFlowChartCustom.php rename Interfaces/Diagrams/{FlowChartInterface.php => FlowInterface.php} (82%) diff --git a/CommonLogic/Debugger/Diagrams/ExtendFlowChart.php b/CommonLogic/Debugger/Diagrams/ExtendFlowChart.php deleted file mode 100644 index 2475dfc6b..000000000 --- a/CommonLogic/Debugger/Diagrams/ExtendFlowChart.php +++ /dev/null @@ -1,12 +0,0 @@ - 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; + + public function addNodeStart($nodeOrTitle, $stringOrStyle = null): FlowNode + { + $node = $this->addNode($nodeOrTitle, $stringOrStyle); + $this->setNodeLast($node); + return $node; // ultimately returns a newly created 'Node' object + } + + /** + * + * @param string|FlowNode $nodeOrTitle + * @param string|object $linkTitleOrObject + * @throws \exface\Core\Exceptions\InvalidArgumentException + * @return \Exface\Core\CommonLogic\Debugger\Diagrams\FlowChart + */ + 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; + } + + 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) { + throw new UnexpectedValueException('TODO'); + } + break; + default: throw new InvalidArgumentException('TODO'); + } + + switch (true) { + case $to instanceof FlowNode: + $toNode = $to; + break; + case is_string($to): + $toNode = $this->findNode($to); + if ($toNode === null) { + throw new UnexpectedValueException('TODO'); + } + break; + default: throw new InvalidArgumentException('TODO'); + } + $link = new FlowLink($fromNode, $toNode, FlowLink::getTitleForAnything($titleOrObject)); + $this->links[] = $link; + return $this; + } + + 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; + } + + // rendering of the complete diagram is done by other subclasses such as MermaidFlowChartCustom + 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; + } +} \ No newline at end of file diff --git a/CommonLogic/Debugger/Diagrams/FlowChart.php b/CommonLogic/Debugger/Diagrams/FlowChart.php deleted file mode 100644 index 33189e7ed..000000000 --- a/CommonLogic/Debugger/Diagrams/FlowChart.php +++ /dev/null @@ -1,84 +0,0 @@ - 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 FlowChart implements FlowChartInterface -{ - // 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; - - public function startNode(string $title): FlowChartNode - { - $node = new FlowChartNode($title); - $this->nodes[] = $node; - $this->lastNode = $node; - return $node; // ultimately returns a newly created 'Node' object - } - - /* - // Possible method to consider in case of adding a Node such as 'Task prefill' - - public function addNode(string $title): FlowChartNode - { - $node = new FlowChartNode($title); - $this->nodes[] = $node; - $this->lastNode = $node; - return $node; - } */ - - public function continue(string $toTitle, string $linkTitle): self - { - $toNode = new FlowChartNode($toTitle); - $this->nodes[] = $toNode; - - if ($this->lastNode !== null) { - $this->addLink($this->lastNode, $toNode, $linkTitle); - } - $this->lastNode = $toNode; - return $this; - } - - protected function addLink(FlowChartNode $from, FlowChartNode $to, string $title): self - { - $link = new FlowChartLink($from, $to, $title); - $this->links[] = $link; - return $this; - } - - public function endNode(string $toTitle, string $linkTitle): void - { - $toNode = new FlowChartNode($toTitle); - $this->nodes[] = $toNode; - if ($this->lastNode !== null) { - $this->addLink($this->lastNode, $toNode, $linkTitle); - } - $this->lastNode = $toNode; - } - - // rendering of the complete diagram is done by other subclasses such as MermaidFlowChartCustom - abstract public function render() : string; - - /** - * Summary of getNodes - * @return FlowChartNode[] - */ - public function getNodes() : array - { - return $this->nodes; - } - - /** - * - * @return FlowChartLink[] - */ - public function getLinks() : array - { - return $this->links; - } -} \ No newline at end of file diff --git a/CommonLogic/Debugger/Diagrams/FlowChartLink.php b/CommonLogic/Debugger/Diagrams/FlowChartLink.php deleted file mode 100644 index fddba9dc7..000000000 --- a/CommonLogic/Debugger/Diagrams/FlowChartLink.php +++ /dev/null @@ -1,37 +0,0 @@ -from = $from; - $this->to = $to; - $this->title = $title; - } - - // returns starting node - public function getNodeFrom(): FlowChartNode - { - return $this->from; - } - - // returns ending node - public function getNodeTo(): FlowChartNode - { - return $this->to; - } - - // returns title of the link - public function getTitle(): string - { - return $this->title; - } -} diff --git a/CommonLogic/Debugger/Diagrams/FlowChartNode.php b/CommonLogic/Debugger/Diagrams/FlowChartNode.php deleted file mode 100644 index 577b0b061..000000000 --- a/CommonLogic/Debugger/Diagrams/FlowChartNode.php +++ /dev/null @@ -1,27 +0,0 @@ -title = $title; - } - - // returns title of node - public function getTitle(): string - { - return $this->title; - } - - // returns style of node - public function getStyle(): FlowChartNodeStyle - { - return $this->style; - } -} diff --git a/CommonLogic/Debugger/Diagrams/FlowLink.php b/CommonLogic/Debugger/Diagrams/FlowLink.php new file mode 100644 index 000000000..d2b7e5864 --- /dev/null +++ b/CommonLogic/Debugger/Diagrams/FlowLink.php @@ -0,0 +1,70 @@ +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; + } +} diff --git a/CommonLogic/Debugger/Diagrams/FlowChartLinkStyle.php b/CommonLogic/Debugger/Diagrams/FlowLinkStyle.php similarity index 79% rename from CommonLogic/Debugger/Diagrams/FlowChartLinkStyle.php rename to CommonLogic/Debugger/Diagrams/FlowLinkStyle.php index 9684d768d..87f130967 100644 --- a/CommonLogic/Debugger/Diagrams/FlowChartLinkStyle.php +++ b/CommonLogic/Debugger/Diagrams/FlowLinkStyle.php @@ -3,12 +3,13 @@ namespace Exface\Core\CommonLogic\Debugger\Diagrams; // holds style properties how a link should be visually represented -class FlowChartLinkStyle +class FlowLinkStyle { - public $name; // name of style - public $stroke; // stroke color - public $arrow; // arrow type - public $weight; // weight or thickness of the link + private $name; // name of style + + private $stroke; // stroke color + private $arrow; // arrow type + private $weight; // weight or thickness of the link public function __construct(string $name, string $stroke, string $arrow, string $weight) { @@ -38,4 +39,5 @@ public function getWeight(): string { return $this->weight; } + } diff --git a/CommonLogic/Debugger/Diagrams/FlowNode.php b/CommonLogic/Debugger/Diagrams/FlowNode.php new file mode 100644 index 000000000..ac621a983 --- /dev/null +++ b/CommonLogic/Debugger/Diagrams/FlowNode.php @@ -0,0 +1,58 @@ +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; + } + + 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; + } +} diff --git a/CommonLogic/Debugger/Diagrams/FlowChartNodeStyle.php b/CommonLogic/Debugger/Diagrams/FlowNodeStyle.php similarity index 62% rename from CommonLogic/Debugger/Diagrams/FlowChartNodeStyle.php rename to CommonLogic/Debugger/Diagrams/FlowNodeStyle.php index 24ba99f0a..365d8733c 100644 --- a/CommonLogic/Debugger/Diagrams/FlowChartNodeStyle.php +++ b/CommonLogic/Debugger/Diagrams/FlowNodeStyle.php @@ -3,15 +3,17 @@ namespace Exface\Core\CommonLogic\Debugger\Diagrams; // holds style properties how a node should be visually represented -class FlowChartNodeStyle +class FlowNodeStyle { + const SHAPE_SQUARE = 'square'; + const SHAPE_ROUND = 'round'; + public $name; // name of style - // TODO what exactly defines rect round etc.? - public $shape; // shape of node (e.g., rect, round) + public $shape; // shape of node (e.g. square, round) public $color; // color of node - public function __construct(string $name, string $shape, string $color) + public function __construct(string $name, string $shape = null, string $color = null) { $this->name = $name; $this->shape = $shape; @@ -24,12 +26,12 @@ public function getName(): string return $this->name; } - public function getShape(): string + public function getShape(): ?string { return $this->shape; } - public function getColor(): string + public function getColor(): ?string { return $this->color; } diff --git a/CommonLogic/Debugger/Diagrams/MermaidFlow.php b/CommonLogic/Debugger/Diagrams/MermaidFlow.php new file mode 100644 index 000000000..51cb20be6 --- /dev/null +++ b/CommonLogic/Debugger/Diagrams/MermaidFlow.php @@ -0,0 +1,70 @@ + Graph::LEFT_RIGHT]); + + foreach ($flowChart->getLinks() as $link) { + $from = $this->addNode($link->getNodeFrom(), $graph); + $to = $this->addNode($link->getNodeTo(), $graph); + $graphLink = new Link($from, $to, $link->getTitle()); + $graph->addLink($graphLink); + } + return $graph->render(); + } + + protected function addNode(FlowNode $node, Graph $graph) : Node + { + $graphNode = new Node($this->getNodeId($node), $node->getTitle(), $this->getNodeForm($node->getStyle())); + $graph->addNode($graphNode); + if ($style = $this->getNodeStyle($node->getStyle())) { + $graph->addStyle('style ' . $this->getNodeId($node) . ' ' . $style); + } + return $graphNode; + } + + protected function getNodeStyle(FlowNodeStyle $nodeStyle = null) : string + { + if ($nodeStyle === null) { + return ''; + } + switch (true) { + case $nodeStyle->getColor() === 'red': + return 'fill:#ef4444,stroke:#ef4444'; + } + return ''; + } + + protected function getNodeForm(FlowNodeStyle $style = null) : string + { + if ($style === null) { + return Node::ROUND; + } + switch ($style->getShape()) { + case FlowNodeStyle::SHAPE_SQUARE: + $form = Node::SQUARE; + break; + case FlowNodeStyle::SHAPE_ROUND: + $form = Node::ROUND; + break; + default: + $form = Node::ROUND; + } + return $form; + } + + protected function getNodeId(FlowNode $node) :string + { + return str_replace(' ', '_', $node->getTitle()); + } +} \ No newline at end of file diff --git a/CommonLogic/Debugger/Diagrams/MermaidFlowChart.php b/CommonLogic/Debugger/Diagrams/MermaidFlowChart.php deleted file mode 100644 index aa7d5daa7..000000000 --- a/CommonLogic/Debugger/Diagrams/MermaidFlowChart.php +++ /dev/null @@ -1,33 +0,0 @@ - Graph::LEFT_RIGHT]); - - foreach ($flowChart->getLinks() as $link) { - // getNodeId: generates a valid Mermaid.js ID for each node - $nodeFromId = new Node($this->getNodeId($link->getNodeFrom()), $link->getNodeFrom()->getTitle()); - $nodeToId = new Node($this->getNodeId($link->getNodeTo()), $link->getNodeTo()->getTitle()); - $graph->addNode($nodeFromId); - $graph->addNode($nodeToId); - $graphLink = new Link($nodeFromId, $nodeToId, $link->getTitle()); - $graph->addLink($graphLink); - } - return $graph->render(); - } - - protected function getNodeId(FlowChartNode $node) :string - { - return str_replace(' ', '_', $node->getTitle()); - } -} \ No newline at end of file diff --git a/CommonLogic/Debugger/Diagrams/MermaidFlowChartCustom.php b/CommonLogic/Debugger/Diagrams/MermaidFlowChartCustom.php deleted file mode 100644 index b2a72d4d4..000000000 --- a/CommonLogic/Debugger/Diagrams/MermaidFlowChartCustom.php +++ /dev/null @@ -1,44 +0,0 @@ -nodes as $node) { - $output .= $this->renderNode($node) . "\n"; - } - foreach ($this->links as $link) { - $output .= $this->renderLink($link) . "\n"; - } - return $output; - } - - // converting a node into a Mermaid.js formatted string - public function renderNode(FlowChartNode $node) : string - { - return "{$this->getNodeId($node)}[{$this->escapeTitle($node->getTitle())}]"; - } - - public function renderLink(FlowChartLink $link) : string - { - // TODO find a new way to display style settings such as dotted etc. - $arrowType = ($link->style->name === "dotted") ?"-.->":"-->"; - return "{$link->getNodeFrom()->getTitle()} {$arrowType}|{$link->getTitle()}| {$link->getNodeTo()->getTitle()}"; - } - - // generates a valid ID for each node - protected function getNodeId(FlowChartNode $node) :string - { - return str_replace(' ', '_', $node->getTitle()); - } - - // special characters in node titles are properly escaped - protected function escapeTitle(string $title) : string - { - return addslashes($title); - } -} \ No newline at end of file diff --git a/Interfaces/Diagrams/FlowChartInterface.php b/Interfaces/Diagrams/FlowInterface.php similarity index 82% rename from Interfaces/Diagrams/FlowChartInterface.php rename to Interfaces/Diagrams/FlowInterface.php index 23848dc02..04319f2e7 100644 --- a/Interfaces/Diagrams/FlowChartInterface.php +++ b/Interfaces/Diagrams/FlowInterface.php @@ -3,7 +3,7 @@ namespace Exface\Core\Interfaces\Diagrams; // -interface FlowChartInterface +interface FlowInterface { public function getLinks(): array; From 252e2d5f82b3ce2e09afbba2e0030e207fdca3fc Mon Sep 17 00:00:00 2001 From: Benjamin Peters Date: Fri, 6 Sep 2024 13:24:08 +0200 Subject: [PATCH 6/7] NEW implementing addNodeEnd method --- CommonLogic/Debugger/Diagrams/Flow.php | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/CommonLogic/Debugger/Diagrams/Flow.php b/CommonLogic/Debugger/Diagrams/Flow.php index f6d4d75e7..063a48a8e 100644 --- a/CommonLogic/Debugger/Diagrams/Flow.php +++ b/CommonLogic/Debugger/Diagrams/Flow.php @@ -21,7 +21,7 @@ public function addNodeStart($nodeOrTitle, $stringOrStyle = null): FlowNode { $node = $this->addNode($nodeOrTitle, $stringOrStyle); $this->setNodeLast($node); - return $node; // ultimately returns a newly created 'Node' object + return $node; } /** @@ -29,7 +29,7 @@ public function addNodeStart($nodeOrTitle, $stringOrStyle = null): FlowNode * @param string|FlowNode $nodeOrTitle * @param string|object $linkTitleOrObject * @throws \exface\Core\Exceptions\InvalidArgumentException - * @return \Exface\Core\CommonLogic\Debugger\Diagrams\FlowChart + * @return \Exface\Core\CommonLogic\Debugger\Diagrams\Flow */ public function continue($nodeOrTitle, $linkTitleOrObject, $stringOrStyle = null): self { @@ -41,6 +41,24 @@ public function continue($nodeOrTitle, $linkTitleOrObject, $stringOrStyle = null $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 { From 8e846290f6fb01c41fe3d573228ea20b6440750f Mon Sep 17 00:00:00 2001 From: Benjamin Peters Date: Fri, 6 Sep 2024 16:23:35 +0200 Subject: [PATCH 7/7] FIX final adjustments such as implementing comments and error handling --- CommonLogic/Debugger/Diagrams/Flow.php | 37 +++++++++++++++---- .../Debugger/Diagrams/FlowLinkStyle.php | 8 ++-- CommonLogic/Debugger/Diagrams/FlowNode.php | 6 ++- .../Debugger/Diagrams/FlowNodeStyle.php | 1 - CommonLogic/Debugger/Diagrams/MermaidFlow.php | 23 +++++++++++- 5 files changed, 61 insertions(+), 14 deletions(-) diff --git a/CommonLogic/Debugger/Diagrams/Flow.php b/CommonLogic/Debugger/Diagrams/Flow.php index 063a48a8e..a7461a698 100644 --- a/CommonLogic/Debugger/Diagrams/Flow.php +++ b/CommonLogic/Debugger/Diagrams/Flow.php @@ -4,10 +4,19 @@ use exface\Core\Exceptions\InvalidArgumentException; use exface\Core\Exceptions\UnexpectedValueException; use exface\Core\Interfaces\Diagrams\FlowInterface; -use JBZoo\MermaidPHP\Node; + +// 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 @@ -17,6 +26,12 @@ abstract class Flow implements FlowInterface // 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); @@ -87,10 +102,11 @@ public function addLink($from, $to, $titleOrObject): self case is_string($from): $fromNode = $this->findNode($from); if ($fromNode === null) { - throw new UnexpectedValueException('TODO'); + $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('TODO'); + default: throw new InvalidArgumentException('Cannot continue flowchart: expecting string or node instance, received ' . gettype($from)); } switch (true) { @@ -99,17 +115,25 @@ public function addLink($from, $to, $titleOrObject): self break; case is_string($to): $toNode = $this->findNode($to); - if ($toNode === null) { - throw new UnexpectedValueException('TODO'); + 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('TODO'); + 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) { @@ -141,7 +165,6 @@ protected function findNode($title) : ?FlowNode return null; } - // rendering of the complete diagram is done by other subclasses such as MermaidFlowChartCustom abstract public function render() : string; /** diff --git a/CommonLogic/Debugger/Diagrams/FlowLinkStyle.php b/CommonLogic/Debugger/Diagrams/FlowLinkStyle.php index 87f130967..66274e096 100644 --- a/CommonLogic/Debugger/Diagrams/FlowLinkStyle.php +++ b/CommonLogic/Debugger/Diagrams/FlowLinkStyle.php @@ -2,16 +2,16 @@ 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 $stroke; // stroke color + 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, string $weight) + public function __construct(string $name, string $stroke, string $arrow = null, string $weight) { $this->name = $name; $this->stroke = $stroke; @@ -27,7 +27,7 @@ public function getName(): string public function getStroke(): string { - return $this->stroke; + return $this->color; } public function getArrow(): string diff --git a/CommonLogic/Debugger/Diagrams/FlowNode.php b/CommonLogic/Debugger/Diagrams/FlowNode.php index ac621a983..7b435d0fd 100644 --- a/CommonLogic/Debugger/Diagrams/FlowNode.php +++ b/CommonLogic/Debugger/Diagrams/FlowNode.php @@ -2,7 +2,6 @@ namespace Exface\Core\CommonLogic\Debugger\Diagrams; -// display a node in the flowchart class FlowNode { const STYLE_SQUARE = 'square'; @@ -39,6 +38,11 @@ public function getStyle(): ?FlowNodeStyle return $this->style; } + /** + * Summary of getStyleFromPreset + * @param string $preset + * @return FlowNodeStyle + */ protected function getStyleFromPreset(string $preset): ?FlowNodeStyle { switch ($preset) { diff --git a/CommonLogic/Debugger/Diagrams/FlowNodeStyle.php b/CommonLogic/Debugger/Diagrams/FlowNodeStyle.php index 365d8733c..1627221bd 100644 --- a/CommonLogic/Debugger/Diagrams/FlowNodeStyle.php +++ b/CommonLogic/Debugger/Diagrams/FlowNodeStyle.php @@ -9,7 +9,6 @@ class FlowNodeStyle const SHAPE_ROUND = 'round'; public $name; // name of style - public $shape; // shape of node (e.g. square, round) public $color; // color of node diff --git a/CommonLogic/Debugger/Diagrams/MermaidFlow.php b/CommonLogic/Debugger/Diagrams/MermaidFlow.php index 51cb20be6..ccdfca8f4 100644 --- a/CommonLogic/Debugger/Diagrams/MermaidFlow.php +++ b/CommonLogic/Debugger/Diagrams/MermaidFlow.php @@ -9,7 +9,12 @@ // renders the flowchart in Mermaid.js syntax class MermaidFlow { - // takes the FlowChartInterface object and converts nodes and links into Mermaid.js + /** + * Summary of render + * @param \exface\Core\Interfaces\Diagrams\FlowInterface $flowChart + * @return string + */ + // takes the FlowInterface object and converts nodes and links into Mermaid.js public function render(FlowInterface $flowChart) : string { $graph = new Graph(['direction' => Graph::LEFT_RIGHT]); @@ -23,6 +28,12 @@ public function render(FlowInterface $flowChart) : string return $graph->render(); } + /** + * Summary of addNode + * @param \exface\Core\CommonLogic\Debugger\Diagrams\FlowNode $node + * @param \JBZoo\MermaidPHP\Graph $graph + * @return \JBZoo\MermaidPHP\Node + */ protected function addNode(FlowNode $node, Graph $graph) : Node { $graphNode = new Node($this->getNodeId($node), $node->getTitle(), $this->getNodeForm($node->getStyle())); @@ -33,6 +44,11 @@ protected function addNode(FlowNode $node, Graph $graph) : Node return $graphNode; } + /** + * Summary of getNodeStyle + * @param \exface\Core\CommonLogic\Debugger\Diagrams\FlowNodeStyle|null $nodeStyle + * @return string + */ protected function getNodeStyle(FlowNodeStyle $nodeStyle = null) : string { if ($nodeStyle === null) { @@ -45,6 +61,11 @@ protected function getNodeStyle(FlowNodeStyle $nodeStyle = null) : string return ''; } + /** + * Summary of getNodeForm + * @param \exface\Core\CommonLogic\Debugger\Diagrams\FlowNodeStyle|null $style + * @return string + */ protected function getNodeForm(FlowNodeStyle $style = null) : string { if ($style === null) {