diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php index fa3c9b284bf06..f84a560c6d44b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php @@ -73,6 +73,7 @@ protected function configure(): void new InputArgument('name', InputArgument::REQUIRED, 'A workflow name'), new InputArgument('marking', InputArgument::IS_ARRAY, 'A marking (a list of places)'), new InputOption('label', 'l', InputOption::VALUE_REQUIRED, 'Label a graph'), + new InputOption('with-metadata', null, InputOption::VALUE_NONE, 'Include the workflow\'s metadata in the dumped graph', null), new InputOption('dump-format', null, InputOption::VALUE_REQUIRED, 'The dump format ['.implode('|', self::DUMP_FORMAT_OPTIONS).']', 'dot'), ]) ->setHelp(<<<'EOF' @@ -134,10 +135,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $options = [ 'name' => $workflowName, + 'with-metadata' => $input->getOption('with-metadata'), 'nofooter' => true, - 'graph' => [ - 'label' => $input->getOption('label'), - ], + 'label' => $input->getOption('label'), ]; $output->writeln($dumper->dump($definition, $marking, $options)); diff --git a/src/Symfony/Component/Workflow/CHANGELOG.md b/src/Symfony/Component/Workflow/CHANGELOG.md index 808ad77eb2e39..ff7162853d0fa 100644 --- a/src/Symfony/Component/Workflow/CHANGELOG.md +++ b/src/Symfony/Component/Workflow/CHANGELOG.md @@ -1,6 +1,12 @@ CHANGELOG ========= +6.4 +--- + + * Add `with-metadata` option to the `workflow:dump` command to include places, + transitions and workflow's metadata into dumped graph + 6.2 --- diff --git a/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php b/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php index 01a5b365910e5..0521a14639c46 100644 --- a/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php +++ b/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php @@ -44,15 +44,19 @@ class GraphvizDumper implements DumperInterface */ public function dump(Definition $definition, Marking $marking = null, array $options = []): string { - $places = $this->findPlaces($definition, $marking); - $transitions = $this->findTransitions($definition); + $withMetadata = $options['with-metadata'] ?? false; + + $places = $this->findPlaces($definition, $withMetadata, $marking); + $transitions = $this->findTransitions($definition, $withMetadata); $edges = $this->findEdges($definition); $options = array_replace_recursive(self::$defaultOptions, $options); - return $this->startDot($options) - .$this->addPlaces($places) - .$this->addTransitions($transitions) + $label = $this->formatLabel($definition, $withMetadata, $options); + + return $this->startDot($options, $label) + .$this->addPlaces($places, $withMetadata) + .$this->addTransitions($transitions, $withMetadata) .$this->addEdges($edges) .$this->endDot(); } @@ -60,7 +64,7 @@ public function dump(Definition $definition, Marking $marking = null, array $opt /** * @internal */ - protected function findPlaces(Definition $definition, Marking $marking = null): array + protected function findPlaces(Definition $definition, bool $withMetadata, Marking $marking = null): array { $workflowMetadata = $definition->getMetadataStore(); @@ -80,9 +84,16 @@ protected function findPlaces(Definition $definition, Marking $marking = null): $attributes['style'] = 'filled'; $attributes['fillcolor'] = $backgroundColor; } + if ($withMetadata) { + $attributes['metadata'] = $workflowMetadata->getPlaceMetadata($place); + } $label = $workflowMetadata->getMetadata('label', $place); if (null !== $label) { $attributes['name'] = $label; + if ($withMetadata) { + // Don't include label in metadata if already used as name + unset($attributes['metadata']['label']); + } } $places[$place] = [ 'attributes' => $attributes, @@ -95,7 +106,7 @@ protected function findPlaces(Definition $definition, Marking $marking = null): /** * @internal */ - protected function findTransitions(Definition $definition): array + protected function findTransitions(Definition $definition, bool $withMetadata): array { $workflowMetadata = $definition->getMetadataStore(); @@ -111,9 +122,16 @@ protected function findTransitions(Definition $definition): array } $name = $workflowMetadata->getMetadata('label', $transition) ?? $transition->getName(); + $metadata = []; + if ($withMetadata) { + $metadata = $workflowMetadata->getTransitionMetadata($transition); + unset($metadata['label']); + } + $transitions[] = [ 'attributes' => $attributes, 'name' => $name, + 'metadata' => $metadata, ]; } @@ -123,7 +141,7 @@ protected function findTransitions(Definition $definition): array /** * @internal */ - protected function addPlaces(array $places): string + protected function addPlaces(array $places, float $withMetadata): string { $code = ''; @@ -135,7 +153,15 @@ protected function addPlaces(array $places): string $placeName = $id; } - $code .= sprintf(" place_%s [label=\"%s\", shape=circle%s];\n", $this->dotize($id), $this->escape($placeName), $this->addAttributes($place['attributes'])); + if ($withMetadata) { + $escapedLabel = sprintf('<%s%s>', $this->escape($placeName), $this->addMetadata($place['attributes']['metadata'])); + // Don't include metadata in default attributes used to format the place + unset($place['attributes']['metadata']); + } else { + $escapedLabel = sprintf('"%s"', $this->escape($placeName)); + } + + $code .= sprintf(" place_%s [label=%s, shape=circle%s];\n", $this->dotize($id), $escapedLabel, $this->addAttributes($place['attributes'])); } return $code; @@ -144,12 +170,18 @@ protected function addPlaces(array $places): string /** * @internal */ - protected function addTransitions(array $transitions): string + protected function addTransitions(array $transitions, bool $withMetadata): string { $code = ''; foreach ($transitions as $i => $place) { - $code .= sprintf(" transition_%s [label=\"%s\",%s];\n", $this->dotize($i), $this->escape($place['name']), $this->addAttributes($place['attributes'])); + if ($withMetadata) { + $escapedLabel = sprintf('<%s%s>', $this->escape($place['name']), $this->addMetadata($place['metadata'])); + } else { + $escapedLabel = '"'.$this->escape($place['name']).'"'; + } + + $code .= sprintf(" transition_%s [label=%s,%s];\n", $this->dotize($i), $escapedLabel, $this->addAttributes($place['attributes'])); } return $code; @@ -215,10 +247,11 @@ protected function addEdges(array $edges): string /** * @internal */ - protected function startDot(array $options): string + protected function startDot(array $options, string $label): string { - return sprintf("digraph workflow {\n %s\n node [%s];\n edge [%s];\n\n", + return sprintf("digraph workflow {\n %s%s\n node [%s];\n edge [%s];\n\n", $this->addOptions($options['graph']), + '""' !== $label && '<>' !== $label ? sprintf(' label=%s', $label) : '', $this->addOptions($options['node']), $this->addOptions($options['edge']) ); @@ -248,6 +281,9 @@ protected function escape(string|bool $value): string return \is_bool($value) ? ($value ? '1' : '0') : addslashes($value); } + /** + * @internal + */ protected function addAttributes(array $attributes): string { $code = []; @@ -259,6 +295,33 @@ protected function addAttributes(array $attributes): string return $code ? ' '.implode(' ', $code) : ''; } + /** + * Handles the label of the graph depending on whether a label was set in CLI, + * if metadata should be included and if there are any. + * + * The produced label must be escaped. + * + * @internal + */ + protected function formatLabel(Definition $definition, string $withMetadata, array $options): string + { + $currentLabel = $options['label'] ?? ''; + + if (!$withMetadata) { + // Only currentLabel to handle. If null, will be translated to empty string + return sprintf('"%s"', $this->escape($currentLabel)); + } + $workflowMetadata = $definition->getMetadataStore()->getWorkflowMetadata(); + + if ('' === $currentLabel) { + // Only metadata to handle + return sprintf('<%s>', $this->addMetadata($workflowMetadata, false)); + } + + // currentLabel and metadata to handle + return sprintf('<%s%s>', $this->escape($currentLabel), $this->addMetadata($workflowMetadata)); + } + private function addOptions(array $options): string { $code = []; @@ -269,4 +332,25 @@ private function addOptions(array $options): string return implode(' ', $code); } + + /** + * @param bool $lineBreakFirstIfNotEmpty Whether to add a separator in the first place when metadata is not empty + */ + private function addMetadata(array $metadata, bool $lineBreakFirstIfNotEmpty = true): string + { + $code = []; + + $skipSeparator = !$lineBreakFirstIfNotEmpty; + + foreach ($metadata as $key => $value) { + if ($skipSeparator) { + $code[] = sprintf('%s: %s', $this->escape($key), $this->escape($value)); + $skipSeparator = false; + } else { + $code[] = sprintf('%s%s: %s', '
', $this->escape($key), $this->escape($value)); + } + } + + return $code ? implode('', $code) : ''; + } } diff --git a/src/Symfony/Component/Workflow/Dumper/StateMachineGraphvizDumper.php b/src/Symfony/Component/Workflow/Dumper/StateMachineGraphvizDumper.php index ac90b61d0f362..a7fda868f7af6 100644 --- a/src/Symfony/Component/Workflow/Dumper/StateMachineGraphvizDumper.php +++ b/src/Symfony/Component/Workflow/Dumper/StateMachineGraphvizDumper.php @@ -27,16 +27,19 @@ class StateMachineGraphvizDumper extends GraphvizDumper */ public function dump(Definition $definition, Marking $marking = null, array $options = []): string { - $places = $this->findPlaces($definition, $marking); + $withMetadata = $options['with-metadata'] ?? false; + + $places = $this->findPlaces($definition, $withMetadata, $marking); $edges = $this->findEdges($definition); $options = array_replace_recursive(self::$defaultOptions, $options); - return $this->startDot($options) - .$this->addPlaces($places) + $label = $this->formatLabel($definition, $withMetadata, $options); + + return $this->startDot($options, $label) + .$this->addPlaces($places, $withMetadata) .$this->addEdges($edges) - .$this->endDot() - ; + .$this->endDot(); } /** diff --git a/src/Symfony/Component/Workflow/Tests/Dumper/GraphvizDumperTest.php b/src/Symfony/Component/Workflow/Tests/Dumper/GraphvizDumperTest.php index ff38822d2235a..aa4b59e5b67fb 100644 --- a/src/Symfony/Component/Workflow/Tests/Dumper/GraphvizDumperTest.php +++ b/src/Symfony/Component/Workflow/Tests/Dumper/GraphvizDumperTest.php @@ -30,9 +30,9 @@ protected function setUp(): void /** * @dataProvider provideWorkflowDefinitionWithoutMarking */ - public function testDumpWithoutMarking($definition, $expected) + public function testDumpWithoutMarking($definition, $expected, $withMetadata) { - $dump = $this->dumper->dump($definition); + $dump = $this->dumper->dump($definition, null, ['with-metadata' => $withMetadata]); $this->assertEquals($expected, $dump); } @@ -40,32 +40,50 @@ public function testDumpWithoutMarking($definition, $expected) /** * @dataProvider provideWorkflowDefinitionWithMarking */ - public function testDumpWithMarking($definition, $marking, $expected) + public function testDumpWithMarking($definition, $marking, $expected, $withMetadata) { - $dump = $this->dumper->dump($definition, $marking); + $dump = $this->dumper->dump($definition, $marking, ['with-metadata' => $withMetadata]); $this->assertEquals($expected, $dump); } + public static function provideWorkflowDefinitionWithoutMarking(): \Generator + { + yield [self::createComplexWorkflowDefinition(), self::provideComplexWorkflowDumpWithoutMarking(), false]; + yield [self::createSimpleWorkflowDefinition(), self::provideSimpleWorkflowDumpWithoutMarking(), false]; + yield [self::createComplexWorkflowDefinition(), self::provideComplexWorkflowDumpWithoutMarkingWithMetadata(), true]; + yield [self::createSimpleWorkflowDefinition(), self::provideSimpleWorkflowDumpWithoutMarkingWithMetadata(), true]; + } + public static function provideWorkflowDefinitionWithMarking(): \Generator { yield [ self::createComplexWorkflowDefinition(), new Marking(['b' => 1]), self::createComplexWorkflowDefinitionDumpWithMarking(), + false, ]; yield [ self::createSimpleWorkflowDefinition(), new Marking(['c' => 1, 'd' => 1]), self::createSimpleWorkflowDumpWithMarking(), + false, ]; - } - public static function provideWorkflowDefinitionWithoutMarking(): \Generator - { - yield [self::createComplexWorkflowDefinition(), self::provideComplexWorkflowDumpWithoutMarking()]; - yield [self::createSimpleWorkflowDefinition(), self::provideSimpleWorkflowDumpWithoutMarking()]; + yield [ + self::createComplexWorkflowDefinition(), + new Marking(['b' => 1]), + self::createComplexWorkflowDefinitionDumpWithMarkingAndMetadata(), + true, + ]; + + yield [ + self::createSimpleWorkflowDefinition(), + new Marking(['c' => 1, 'd' => 1]), + self::createSimpleWorkflowDumpWithMarkingAndMetadata(), + true, + ]; } public static function createComplexWorkflowDefinitionDumpWithMarking(): string @@ -106,6 +124,44 @@ public static function createComplexWorkflowDefinitionDumpWithMarking(): string '; } + public static function createComplexWorkflowDefinitionDumpWithMarkingAndMetadata(): string + { + return 'digraph workflow { + ratio="compress" rankdir="LR" + node [fontsize="9" fontname="Arial" color="#333333" fillcolor="lightblue" fixedsize="false" width="1"]; + edge [fontsize="9" fontname="Arial" color="#333333" arrowhead="normal" arrowsize="0.5"]; + + place_86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 [label=<a>, shape=circle style="filled"]; + place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [label=<b>, shape=circle color="#FF0000" shape="doublecircle"]; + place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [label=<c>, shape=circle]; + place_3c363836cf4e16666669a25da280a1865c2d2874 [label=<d>, shape=circle]; + place_58e6b3a414a1e090dfc6029add0f3555ccba127f [label=<e>, shape=circle]; + place_4a0a19218e082a343a1b17e5333409af9d98f0f5 [label=<f>, shape=circle]; + place_54fd1711209fb1c0781092374132c66e79e2241b [label=<g>, shape=circle]; + transition_b6589fc6ab0dc82cf12099d1c2d40ab994e8410c [label=<t1>, shape="box" regular="1"]; + transition_356a192b7913b04c54574d18c28d46e6395428ab [label=<t2>, shape="box" regular="1"]; + transition_da4b9237bacccdf19c0760cab7aec4a8359010b0 [label=<My custom transition label 1
color: Red
arrow_color: Green>, shape="box" regular="1"]; + transition_77de68daecd823babbb58edb1c8e14d7106e83bb [label=<t4>, shape="box" regular="1"]; + transition_1b6453892473a467d07372d45eb05abc2031647a [label=<t5>, shape="box" regular="1"]; + transition_ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4 [label=<t6>, shape="box" regular="1"]; + place_86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 -> transition_b6589fc6ab0dc82cf12099d1c2d40ab994e8410c [style="solid"]; + transition_b6589fc6ab0dc82cf12099d1c2d40ab994e8410c -> place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [style="solid"]; + transition_b6589fc6ab0dc82cf12099d1c2d40ab994e8410c -> place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [style="solid"]; + place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 -> transition_356a192b7913b04c54574d18c28d46e6395428ab [style="solid"]; + place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 -> transition_356a192b7913b04c54574d18c28d46e6395428ab [style="solid"]; + transition_356a192b7913b04c54574d18c28d46e6395428ab -> place_3c363836cf4e16666669a25da280a1865c2d2874 [style="solid"]; + place_3c363836cf4e16666669a25da280a1865c2d2874 -> transition_da4b9237bacccdf19c0760cab7aec4a8359010b0 [style="solid"]; + transition_da4b9237bacccdf19c0760cab7aec4a8359010b0 -> place_58e6b3a414a1e090dfc6029add0f3555ccba127f [style="solid"]; + place_3c363836cf4e16666669a25da280a1865c2d2874 -> transition_77de68daecd823babbb58edb1c8e14d7106e83bb [style="solid"]; + transition_77de68daecd823babbb58edb1c8e14d7106e83bb -> place_4a0a19218e082a343a1b17e5333409af9d98f0f5 [style="solid"]; + place_58e6b3a414a1e090dfc6029add0f3555ccba127f -> transition_1b6453892473a467d07372d45eb05abc2031647a [style="solid"]; + transition_1b6453892473a467d07372d45eb05abc2031647a -> place_54fd1711209fb1c0781092374132c66e79e2241b [style="solid"]; + place_4a0a19218e082a343a1b17e5333409af9d98f0f5 -> transition_ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4 [style="solid"]; + transition_ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4 -> place_54fd1711209fb1c0781092374132c66e79e2241b [style="solid"]; +} +'; + } + public static function createSimpleWorkflowDumpWithMarking(): string { return 'digraph workflow { @@ -126,6 +182,26 @@ public static function createSimpleWorkflowDumpWithMarking(): string '; } + public static function createSimpleWorkflowDumpWithMarkingAndMetadata(): string + { + return 'digraph workflow { + ratio="compress" rankdir="LR" + node [fontsize="9" fontname="Arial" color="#333333" fillcolor="lightblue" fixedsize="false" width="1"]; + edge [fontsize="9" fontname="Arial" color="#333333" arrowhead="normal" arrowsize="0.5"]; + + place_86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 [label=<a>, shape=circle style="filled"]; + place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [label=<b>, shape=circle]; + place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [label=<c
bg_color: DeepSkyBlue
description: My custom place description>, shape=circle color="#FF0000" shape="doublecircle" style="filled" fillcolor="DeepSkyBlue"]; + transition_b6589fc6ab0dc82cf12099d1c2d40ab994e8410c [label=<My custom transition label 2
color: Grey
arrow_color: Purple>, shape="box" regular="1"]; + transition_356a192b7913b04c54574d18c28d46e6395428ab [label=<t2
arrow_color: Pink>, shape="box" regular="1"]; + place_86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 -> transition_b6589fc6ab0dc82cf12099d1c2d40ab994e8410c [style="solid"]; + transition_b6589fc6ab0dc82cf12099d1c2d40ab994e8410c -> place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [style="solid"]; + place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 -> transition_356a192b7913b04c54574d18c28d46e6395428ab [style="solid"]; + transition_356a192b7913b04c54574d18c28d46e6395428ab -> place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [style="solid"]; +} +'; + } + public static function provideComplexWorkflowDumpWithoutMarking(): string { return 'digraph workflow { @@ -164,6 +240,44 @@ public static function provideComplexWorkflowDumpWithoutMarking(): string '; } + public static function provideComplexWorkflowDumpWithoutMarkingWithMetadata(): string + { + return 'digraph workflow { + ratio="compress" rankdir="LR" + node [fontsize="9" fontname="Arial" color="#333333" fillcolor="lightblue" fixedsize="false" width="1"]; + edge [fontsize="9" fontname="Arial" color="#333333" arrowhead="normal" arrowsize="0.5"]; + + place_86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 [label=<a>, shape=circle style="filled"]; + place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [label=<b>, shape=circle]; + place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [label=<c>, shape=circle]; + place_3c363836cf4e16666669a25da280a1865c2d2874 [label=<d>, shape=circle]; + place_58e6b3a414a1e090dfc6029add0f3555ccba127f [label=<e>, shape=circle]; + place_4a0a19218e082a343a1b17e5333409af9d98f0f5 [label=<f>, shape=circle]; + place_54fd1711209fb1c0781092374132c66e79e2241b [label=<g>, shape=circle]; + transition_b6589fc6ab0dc82cf12099d1c2d40ab994e8410c [label=<t1>, shape="box" regular="1"]; + transition_356a192b7913b04c54574d18c28d46e6395428ab [label=<t2>, shape="box" regular="1"]; + transition_da4b9237bacccdf19c0760cab7aec4a8359010b0 [label=<My custom transition label 1
color: Red
arrow_color: Green>, shape="box" regular="1"]; + transition_77de68daecd823babbb58edb1c8e14d7106e83bb [label=<t4>, shape="box" regular="1"]; + transition_1b6453892473a467d07372d45eb05abc2031647a [label=<t5>, shape="box" regular="1"]; + transition_ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4 [label=<t6>, shape="box" regular="1"]; + place_86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 -> transition_b6589fc6ab0dc82cf12099d1c2d40ab994e8410c [style="solid"]; + transition_b6589fc6ab0dc82cf12099d1c2d40ab994e8410c -> place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [style="solid"]; + transition_b6589fc6ab0dc82cf12099d1c2d40ab994e8410c -> place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [style="solid"]; + place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 -> transition_356a192b7913b04c54574d18c28d46e6395428ab [style="solid"]; + place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 -> transition_356a192b7913b04c54574d18c28d46e6395428ab [style="solid"]; + transition_356a192b7913b04c54574d18c28d46e6395428ab -> place_3c363836cf4e16666669a25da280a1865c2d2874 [style="solid"]; + place_3c363836cf4e16666669a25da280a1865c2d2874 -> transition_da4b9237bacccdf19c0760cab7aec4a8359010b0 [style="solid"]; + transition_da4b9237bacccdf19c0760cab7aec4a8359010b0 -> place_58e6b3a414a1e090dfc6029add0f3555ccba127f [style="solid"]; + place_3c363836cf4e16666669a25da280a1865c2d2874 -> transition_77de68daecd823babbb58edb1c8e14d7106e83bb [style="solid"]; + transition_77de68daecd823babbb58edb1c8e14d7106e83bb -> place_4a0a19218e082a343a1b17e5333409af9d98f0f5 [style="solid"]; + place_58e6b3a414a1e090dfc6029add0f3555ccba127f -> transition_1b6453892473a467d07372d45eb05abc2031647a [style="solid"]; + transition_1b6453892473a467d07372d45eb05abc2031647a -> place_54fd1711209fb1c0781092374132c66e79e2241b [style="solid"]; + place_4a0a19218e082a343a1b17e5333409af9d98f0f5 -> transition_ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4 [style="solid"]; + transition_ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4 -> place_54fd1711209fb1c0781092374132c66e79e2241b [style="solid"]; +} +'; + } + public static function provideSimpleWorkflowDumpWithoutMarking(): string { return 'digraph workflow { @@ -181,6 +295,26 @@ public static function provideSimpleWorkflowDumpWithoutMarking(): string place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 -> transition_356a192b7913b04c54574d18c28d46e6395428ab [style="solid"]; transition_356a192b7913b04c54574d18c28d46e6395428ab -> place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [style="solid"]; } +'; + } + + public static function provideSimpleWorkflowDumpWithoutMarkingWithMetadata(): string + { + return 'digraph workflow { + ratio="compress" rankdir="LR" + node [fontsize="9" fontname="Arial" color="#333333" fillcolor="lightblue" fixedsize="false" width="1"]; + edge [fontsize="9" fontname="Arial" color="#333333" arrowhead="normal" arrowsize="0.5"]; + + place_86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 [label=<a>, shape=circle style="filled"]; + place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [label=<b>, shape=circle]; + place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [label=<c
bg_color: DeepSkyBlue
description: My custom place description>, shape=circle style="filled" fillcolor="DeepSkyBlue"]; + transition_b6589fc6ab0dc82cf12099d1c2d40ab994e8410c [label=<My custom transition label 2
color: Grey
arrow_color: Purple>, shape="box" regular="1"]; + transition_356a192b7913b04c54574d18c28d46e6395428ab [label=<t2
arrow_color: Pink>, shape="box" regular="1"]; + place_86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 -> transition_b6589fc6ab0dc82cf12099d1c2d40ab994e8410c [style="solid"]; + transition_b6589fc6ab0dc82cf12099d1c2d40ab994e8410c -> place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [style="solid"]; + place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 -> transition_356a192b7913b04c54574d18c28d46e6395428ab [style="solid"]; + transition_356a192b7913b04c54574d18c28d46e6395428ab -> place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [style="solid"]; +} '; } }