diff --git a/src/Symfony/Component/Workflow/CHANGELOG.md b/src/Symfony/Component/Workflow/CHANGELOG.md index 7e54a59a61..f7a7275bd2 100644 --- a/src/Symfony/Component/Workflow/CHANGELOG.md +++ b/src/Symfony/Component/Workflow/CHANGELOG.md @@ -6,6 +6,19 @@ CHANGELOG * Trigger `entered` event for subject entering in the Workflow for the first time * Added a context to `Workflow::apply()`. The `MethodMarkingStore` could be used to leverage this feature. + * Add style to transitions by declaring metadata: + ``` + $places = range('a', 'b'); + $transition = new Transition('t1', 'a', 'b'); + $transitions[] = $transition; + $transitionsMetadata = new \SplObjectStorage(); + $transitionsMetadata[$transition] = [ + 'color' => 'Red', + 'arrow_color' => '#00ff00', + ]; + $inMemoryMetadataStore = new InMemoryMetadataStore([], [], $transitionsMetadata); + return new Definition($places, $transitions, null, $inMemoryMetadataStore); + ``` 4.1.0 ----- diff --git a/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php b/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php index 918c0c8335..6822eab86b 100644 --- a/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php +++ b/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php @@ -63,6 +63,8 @@ class GraphvizDumper implements DumperInterface */ protected function findPlaces(Definition $definition, Marking $marking = null) { + $workflowMetadata = $definition->getMetadataStore(); + $places = []; foreach ($definition->getPlaces() as $place) { @@ -74,6 +76,15 @@ class GraphvizDumper implements DumperInterface $attributes['color'] = '#FF0000'; $attributes['shape'] = 'doublecircle'; } + $backgroundColor = $workflowMetadata->getMetadata('bg_color', $place); + if (null !== $backgroundColor) { + $attributes['style'] = 'filled'; + $attributes['fillcolor'] = $backgroundColor; + } + $label = $workflowMetadata->getMetadata('label', $place); + if (null !== $label) { + $attributes['name'] = $label; + } $places[$place] = [ 'attributes' => $attributes, ]; @@ -87,12 +98,23 @@ class GraphvizDumper implements DumperInterface */ protected function findTransitions(Definition $definition) { + $workflowMetadata = $definition->getMetadataStore(); + $transitions = []; foreach ($definition->getTransitions() as $transition) { + $attributes = ['shape' => 'box', 'regular' => true]; + + $backgroundColor = $workflowMetadata->getMetadata('bg_color', $transition); + if (null !== $backgroundColor) { + $attributes['style'] = 'filled'; + $attributes['fillcolor'] = $backgroundColor; + } + $name = $workflowMetadata->getMetadata('label', $transition) ?? $transition->getName(); + $transitions[] = [ - 'attributes' => ['shape' => 'box', 'regular' => true], - 'name' => $transition->getName(), + 'attributes' => $attributes, + 'name' => $name, ]; } @@ -107,7 +129,14 @@ class GraphvizDumper implements DumperInterface $code = ''; foreach ($places as $id => $place) { - $code .= sprintf(" place_%s [label=\"%s\", shape=circle%s];\n", $this->dotize($id), $this->escape($id), $this->addAttributes($place['attributes'])); + if (isset($place['attributes']['name'])) { + $placeName = $place['attributes']['name']; + unset($place['attributes']['name']); + } else { + $placeName = $id; + } + + $code .= sprintf(" place_%s [label=\"%s\", shape=circle%s];\n", $this->dotize($id), $this->escape($placeName), $this->addAttributes($place['attributes'])); } return $code; @@ -121,7 +150,7 @@ class GraphvizDumper implements DumperInterface $code = ''; foreach ($transitions as $place) { - $code .= sprintf(" transition_%s [label=\"%s\", shape=box%s];\n", $this->dotize($place['name']), $this->escape($place['name']), $this->addAttributes($place['attributes'])); + $code .= sprintf(" transition_%s [label=\"%s\",%s];\n", $this->dotize($place['name']), $this->escape($place['name']), $this->addAttributes($place['attributes'])); } return $code; @@ -132,19 +161,23 @@ class GraphvizDumper implements DumperInterface */ protected function findEdges(Definition $definition) { + $workflowMetadata = $definition->getMetadataStore(); + $dotEdges = []; foreach ($definition->getTransitions() as $transition) { + $transitionName = $workflowMetadata->getMetadata('label', $transition) ?? $transition->getName(); + foreach ($transition->getFroms() as $from) { $dotEdges[] = [ 'from' => $from, - 'to' => $transition->getName(), + 'to' => $transitionName, 'direction' => 'from', ]; } foreach ($transition->getTos() as $to) { $dotEdges[] = [ - 'from' => $transition->getName(), + 'from' => $transitionName, 'to' => $to, 'direction' => 'to', ]; @@ -209,7 +242,7 @@ class GraphvizDumper implements DumperInterface return \is_bool($value) ? ($value ? '1' : '0') : \addslashes($value); } - private function addAttributes(array $attributes): string + protected function addAttributes(array $attributes): string { $code = []; @@ -217,7 +250,7 @@ class GraphvizDumper implements DumperInterface $code[] = sprintf('%s="%s"', $k, $this->escape($v)); } - return $code ? ', '.implode(', ', $code) : ''; + return $code ? ' '.implode(' ', $code) : ''; } private function addOptions(array $options): string diff --git a/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php b/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php index e5e3869824..50d9046f26 100644 --- a/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php +++ b/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php @@ -14,6 +14,8 @@ namespace Symfony\Component\Workflow\Dumper; use InvalidArgumentException; use Symfony\Component\Workflow\Definition; use Symfony\Component\Workflow\Marking; +use Symfony\Component\Workflow\Metadata\MetadataStoreInterface; +use Symfony\Component\Workflow\Transition; /** * PlantUmlDumper dumps a workflow as a PlantUML file. @@ -63,13 +65,13 @@ class PlantUmlDumper implements DumperInterface public function dump(Definition $definition, Marking $marking = null, array $options = []): string { $options = array_replace_recursive(self::DEFAULT_OPTIONS, $options); - $code = $this->initialize($options); + + $workflowMetadata = $definition->getMetadataStore(); + + $code = $this->initialize($options, $definition); + foreach ($definition->getPlaces() as $place) { - $placeEscaped = $this->escape($place); - $code[] = - "state $placeEscaped". - ($definition->getInitialPlace() === $place ? ' '.self::INITIAL : ''). - ($marking && $marking->has($place) ? ' '.self::MARKED : ''); + $code[] = $this->getState($place, $definition, $marking); } if ($this->isWorkflowTransitionType()) { foreach ($definition->getTransitions() as $transition) { @@ -83,10 +85,26 @@ class PlantUmlDumper implements DumperInterface $fromEscaped = $this->escape($from); foreach ($transition->getTos() as $to) { $toEscaped = $this->escape($to); + + $transitionEscapedWithStyle = $this->getTransitionEscapedWithStyle($workflowMetadata, $transition, $transitionEscaped); + + $arrowColor = $workflowMetadata->getMetadata('arrow_color', $transition); + + $transitionColor = ''; + if (null !== $arrowColor) { + $transitionColor = $this->getTransitionColor($arrowColor) ?? ''; + } + if ($this->isWorkflowTransitionType()) { + $transitionLabel = ''; + // Add label only if it has a style + if ($transitionEscapedWithStyle != $transitionEscaped) { + $transitionLabel = ": $transitionEscapedWithStyle"; + } + $lines = [ - "$fromEscaped --> $transitionEscaped", - "$transitionEscaped --> $toEscaped", + "$fromEscaped -${transitionColor}-> ${transitionEscaped}${transitionLabel}", + "$transitionEscaped -${transitionColor}-> ${toEscaped}${transitionLabel}", ]; foreach ($lines as $line) { if (!\in_array($line, $code)) { @@ -94,7 +112,7 @@ class PlantUmlDumper implements DumperInterface } } } else { - $code[] = "$fromEscaped --> $toEscaped: $transitionEscaped"; + $code[] = "$fromEscaped -${transitionColor}-> $toEscaped: $transitionEscapedWithStyle"; } } } @@ -126,8 +144,10 @@ class PlantUmlDumper implements DumperInterface return implode(PHP_EOL, $code); } - private function initialize(array $options): array + private function initialize(array $options, Definition $definition): array { + $workflowMetadata = $definition->getMetadataStore(); + $code = []; if (isset($options['title'])) { $code[] = "title {$options['title']}"; @@ -135,6 +155,17 @@ class PlantUmlDumper implements DumperInterface if (isset($options['name'])) { $code[] = "title {$options['name']}"; } + + // Add style from nodes + foreach ($definition->getPlaces() as $place) { + $backgroundColor = $workflowMetadata->getMetadata('bg_color', $place); + if (null !== $backgroundColor) { + $key = 'BackgroundColor<<'.$this->getColorId($backgroundColor).'>>'; + + $options['skinparams']['state'][$key] = $backgroundColor; + } + } + if (isset($options['skinparams']) && \is_array($options['skinparams'])) { foreach ($options['skinparams'] as $skinparamKey => $skinparamValue) { if (!$this->isWorkflowTransitionType() && 'agent' === $skinparamKey) { @@ -160,4 +191,62 @@ class PlantUmlDumper implements DumperInterface // It's not possible to escape property double quote, so let's remove it return '"'.str_replace('"', '', $string).'"'; } + + private function getState(string $place, Definition $definition, Marking $marking = null): string + { + $workflowMetadata = $definition->getMetadataStore(); + + $placeEscaped = $this->escape($place); + + $output = "state $placeEscaped". + ($definition->getInitialPlace() === $place ? ' '.self::INITIAL : ''). + ($marking && $marking->has($place) ? ' '.self::MARKED : ''); + + $backgroundColor = $workflowMetadata->getMetadata('bg_color', $place); + if (null !== $backgroundColor) { + $output .= ' <<'.$this->getColorId($backgroundColor).'>>'; + } + + $description = $workflowMetadata->getMetadata('description', $place); + if (null !== $description) { + $output .= ' as '.$place. + PHP_EOL. + $place.' : '.$description; + } + + return $output; + } + + private function getTransitionEscapedWithStyle(MetadataStoreInterface $workflowMetadata, Transition $transition, string $to): string + { + $to = $workflowMetadata->getMetadata('label', $transition) ?? $to; + + $color = $workflowMetadata->getMetadata('color', $transition) ?? null; + + if (null !== $color) { + $to = sprintf( + '%2$s', + $color, + $to + ); + } + + return $this->escape($to); + } + + private function getTransitionColor(string $color): string + { + // PUML format requires that color in transition have to be prefixed with “#”. + if ('#' !== substr($color, 0, 1)) { + $color = '#'.$color; + } + + return sprintf('[%s]', $color); + } + + private function getColorId(string $color): string + { + // Remove “#“ from start of the color name so it can be used as an identifier. + return ltrim($color, '#'); + } } diff --git a/src/Symfony/Component/Workflow/Dumper/StateMachineGraphvizDumper.php b/src/Symfony/Component/Workflow/Dumper/StateMachineGraphvizDumper.php index dac6730de8..56ec2697be 100644 --- a/src/Symfony/Component/Workflow/Dumper/StateMachineGraphvizDumper.php +++ b/src/Symfony/Component/Workflow/Dumper/StateMachineGraphvizDumper.php @@ -46,15 +46,32 @@ class StateMachineGraphvizDumper extends GraphvizDumper */ protected function findEdges(Definition $definition) { + $workflowMetadata = $definition->getMetadataStore(); + $edges = []; foreach ($definition->getTransitions() as $transition) { + $attributes = []; + + $transitionName = $workflowMetadata->getMetadata('label', $transition) ?? $transition->getName(); + + $labelColor = $workflowMetadata->getMetadata('color', $transition); + if (null !== $labelColor) { + $attributes['fontcolor'] = $labelColor; + } + $arrowColor = $workflowMetadata->getMetadata('arrow_color', $transition); + if (null !== $arrowColor) { + $attributes['color'] = $arrowColor; + } + foreach ($transition->getFroms() as $from) { foreach ($transition->getTos() as $to) { - $edges[$from][] = [ - 'name' => $transition->getName(), + $edge = [ + 'name' => $transitionName, 'to' => $to, + 'attributes' => $attributes, ]; + $edges[$from][] = $edge; } } } @@ -71,7 +88,14 @@ class StateMachineGraphvizDumper extends GraphvizDumper foreach ($edges as $id => $edges) { foreach ($edges as $edge) { - $code .= sprintf(" place_%s -> place_%s [label=\"%s\" style=\"%s\"];\n", $this->dotize($id), $this->dotize($edge['to']), $this->escape($edge['name']), 'solid'); + $code .= sprintf( + " place_%s -> place_%s [label=\"%s\" style=\"%s\"%s];\n", + $this->dotize($id), + $this->dotize($edge['to']), + $this->escape($edge['name']), + 'solid', + $this->addAttributes($edge['attributes']) + ); } } diff --git a/src/Symfony/Component/Workflow/Tests/Dumper/GraphvizDumperTest.php b/src/Symfony/Component/Workflow/Tests/Dumper/GraphvizDumperTest.php index 0d14404d2e..f73918cc6b 100644 --- a/src/Symfony/Component/Workflow/Tests/Dumper/GraphvizDumperTest.php +++ b/src/Symfony/Component/Workflow/Tests/Dumper/GraphvizDumperTest.php @@ -66,27 +66,27 @@ class GraphvizDumperTest extends TestCase 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_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_e5353879bd69bfddcb465dad176ff52db8319d6f [label="t1", shape=box, shape="box", regular="1"]; - transition_2a5bd02710e975a7fbb92da876655950fbd5e70d [label="t2", shape=box, shape="box", regular="1"]; - transition_4358694eeb098c6708ae914a10562ce722bbbc34 [label="t3", shape=box, shape="box", regular="1"]; - transition_a9dfb15be45a5f3128784c80c733f2cdee2f756a [label="t4", shape=box, shape="box", regular="1"]; - transition_bf55e75fa263cbbc2529db49da43cb7f1d370b88 [label="t5", shape=box, shape="box", regular="1"]; - transition_e92a96c0e3a20d87ace74ab7871931a8f9f25943 [label="t6", shape=box, shape="box", regular="1"]; + transition_e5353879bd69bfddcb465dad176ff52db8319d6f [label="t1", shape="box" regular="1"]; + transition_2a5bd02710e975a7fbb92da876655950fbd5e70d [label="t2", shape="box" regular="1"]; + transition_0e93386f7fc29aa558e22918bd39c3de8c84f6d8 [label="My custom transition label 1", shape="box" regular="1"]; + transition_a9dfb15be45a5f3128784c80c733f2cdee2f756a [label="t4", shape="box" regular="1"]; + transition_bf55e75fa263cbbc2529db49da43cb7f1d370b88 [label="t5", shape="box" regular="1"]; + transition_e92a96c0e3a20d87ace74ab7871931a8f9f25943 [label="t6", shape="box" regular="1"]; place_86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 -> transition_e5353879bd69bfddcb465dad176ff52db8319d6f [style="solid"]; transition_e5353879bd69bfddcb465dad176ff52db8319d6f -> place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [style="solid"]; transition_e5353879bd69bfddcb465dad176ff52db8319d6f -> place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [style="solid"]; place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 -> transition_2a5bd02710e975a7fbb92da876655950fbd5e70d [style="solid"]; place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 -> transition_2a5bd02710e975a7fbb92da876655950fbd5e70d [style="solid"]; transition_2a5bd02710e975a7fbb92da876655950fbd5e70d -> place_3c363836cf4e16666669a25da280a1865c2d2874 [style="solid"]; - place_3c363836cf4e16666669a25da280a1865c2d2874 -> transition_4358694eeb098c6708ae914a10562ce722bbbc34 [style="solid"]; - transition_4358694eeb098c6708ae914a10562ce722bbbc34 -> place_58e6b3a414a1e090dfc6029add0f3555ccba127f [style="solid"]; + place_3c363836cf4e16666669a25da280a1865c2d2874 -> transition_0e93386f7fc29aa558e22918bd39c3de8c84f6d8 [style="solid"]; + transition_0e93386f7fc29aa558e22918bd39c3de8c84f6d8 -> place_58e6b3a414a1e090dfc6029add0f3555ccba127f [style="solid"]; place_3c363836cf4e16666669a25da280a1865c2d2874 -> transition_a9dfb15be45a5f3128784c80c733f2cdee2f756a [style="solid"]; transition_a9dfb15be45a5f3128784c80c733f2cdee2f756a -> place_4a0a19218e082a343a1b17e5333409af9d98f0f5 [style="solid"]; place_58e6b3a414a1e090dfc6029add0f3555ccba127f -> transition_bf55e75fa263cbbc2529db49da43cb7f1d370b88 [style="solid"]; @@ -104,13 +104,13 @@ class GraphvizDumperTest extends TestCase 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_86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 [label="a", shape=circle style="filled"]; place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [label="b", shape=circle]; - place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [label="c", shape=circle, color="#FF0000", shape="doublecircle"]; - transition_e5353879bd69bfddcb465dad176ff52db8319d6f [label="t1", shape=box, shape="box", regular="1"]; - transition_2a5bd02710e975a7fbb92da876655950fbd5e70d [label="t2", shape=box, shape="box", regular="1"]; - place_86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 -> transition_e5353879bd69bfddcb465dad176ff52db8319d6f [style="solid"]; - transition_e5353879bd69bfddcb465dad176ff52db8319d6f -> place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [style="solid"]; + place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [label="c", shape=circle color="#FF0000" shape="doublecircle" style="filled" fillcolor="DeepSkyBlue"]; + transition_805bac6f9261aaae4068bf114e182e9c37e2728d [label="My custom transition label 2", shape="box" regular="1"]; + transition_2a5bd02710e975a7fbb92da876655950fbd5e70d [label="t2", shape="box" regular="1"]; + place_86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 -> transition_805bac6f9261aaae4068bf114e182e9c37e2728d [style="solid"]; + transition_805bac6f9261aaae4068bf114e182e9c37e2728d -> place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [style="solid"]; place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 -> transition_2a5bd02710e975a7fbb92da876655950fbd5e70d [style="solid"]; transition_2a5bd02710e975a7fbb92da876655950fbd5e70d -> place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [style="solid"]; } @@ -124,27 +124,27 @@ class GraphvizDumperTest extends TestCase 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_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_e5353879bd69bfddcb465dad176ff52db8319d6f [label="t1", shape=box, shape="box", regular="1"]; - transition_2a5bd02710e975a7fbb92da876655950fbd5e70d [label="t2", shape=box, shape="box", regular="1"]; - transition_4358694eeb098c6708ae914a10562ce722bbbc34 [label="t3", shape=box, shape="box", regular="1"]; - transition_a9dfb15be45a5f3128784c80c733f2cdee2f756a [label="t4", shape=box, shape="box", regular="1"]; - transition_bf55e75fa263cbbc2529db49da43cb7f1d370b88 [label="t5", shape=box, shape="box", regular="1"]; - transition_e92a96c0e3a20d87ace74ab7871931a8f9f25943 [label="t6", shape=box, shape="box", regular="1"]; + transition_e5353879bd69bfddcb465dad176ff52db8319d6f [label="t1", shape="box" regular="1"]; + transition_2a5bd02710e975a7fbb92da876655950fbd5e70d [label="t2", shape="box" regular="1"]; + transition_0e93386f7fc29aa558e22918bd39c3de8c84f6d8 [label="My custom transition label 1", shape="box" regular="1"]; + transition_a9dfb15be45a5f3128784c80c733f2cdee2f756a [label="t4", shape="box" regular="1"]; + transition_bf55e75fa263cbbc2529db49da43cb7f1d370b88 [label="t5", shape="box" regular="1"]; + transition_e92a96c0e3a20d87ace74ab7871931a8f9f25943 [label="t6", shape="box" regular="1"]; place_86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 -> transition_e5353879bd69bfddcb465dad176ff52db8319d6f [style="solid"]; transition_e5353879bd69bfddcb465dad176ff52db8319d6f -> place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [style="solid"]; transition_e5353879bd69bfddcb465dad176ff52db8319d6f -> place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [style="solid"]; place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 -> transition_2a5bd02710e975a7fbb92da876655950fbd5e70d [style="solid"]; place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 -> transition_2a5bd02710e975a7fbb92da876655950fbd5e70d [style="solid"]; transition_2a5bd02710e975a7fbb92da876655950fbd5e70d -> place_3c363836cf4e16666669a25da280a1865c2d2874 [style="solid"]; - place_3c363836cf4e16666669a25da280a1865c2d2874 -> transition_4358694eeb098c6708ae914a10562ce722bbbc34 [style="solid"]; - transition_4358694eeb098c6708ae914a10562ce722bbbc34 -> place_58e6b3a414a1e090dfc6029add0f3555ccba127f [style="solid"]; + place_3c363836cf4e16666669a25da280a1865c2d2874 -> transition_0e93386f7fc29aa558e22918bd39c3de8c84f6d8 [style="solid"]; + transition_0e93386f7fc29aa558e22918bd39c3de8c84f6d8 -> place_58e6b3a414a1e090dfc6029add0f3555ccba127f [style="solid"]; place_3c363836cf4e16666669a25da280a1865c2d2874 -> transition_a9dfb15be45a5f3128784c80c733f2cdee2f756a [style="solid"]; transition_a9dfb15be45a5f3128784c80c733f2cdee2f756a -> place_4a0a19218e082a343a1b17e5333409af9d98f0f5 [style="solid"]; place_58e6b3a414a1e090dfc6029add0f3555ccba127f -> transition_bf55e75fa263cbbc2529db49da43cb7f1d370b88 [style="solid"]; @@ -162,13 +162,13 @@ class GraphvizDumperTest extends TestCase 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_86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 [label="a", shape=circle style="filled"]; place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [label="b", shape=circle]; - place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [label="c", shape=circle]; - transition_e5353879bd69bfddcb465dad176ff52db8319d6f [label="t1", shape=box, shape="box", regular="1"]; - transition_2a5bd02710e975a7fbb92da876655950fbd5e70d [label="t2", shape=box, shape="box", regular="1"]; - place_86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 -> transition_e5353879bd69bfddcb465dad176ff52db8319d6f [style="solid"]; - transition_e5353879bd69bfddcb465dad176ff52db8319d6f -> place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [style="solid"]; + place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [label="c", shape=circle style="filled" fillcolor="DeepSkyBlue"]; + transition_805bac6f9261aaae4068bf114e182e9c37e2728d [label="My custom transition label 2", shape="box" regular="1"]; + transition_2a5bd02710e975a7fbb92da876655950fbd5e70d [label="t2", shape="box" regular="1"]; + place_86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 -> transition_805bac6f9261aaae4068bf114e182e9c37e2728d [style="solid"]; + transition_805bac6f9261aaae4068bf114e182e9c37e2728d -> place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [style="solid"]; place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 -> transition_2a5bd02710e975a7fbb92da876655950fbd5e70d [style="solid"]; transition_2a5bd02710e975a7fbb92da876655950fbd5e70d -> place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [style="solid"]; } diff --git a/src/Symfony/Component/Workflow/Tests/Dumper/StateMachineGraphvizDumperTest.php b/src/Symfony/Component/Workflow/Tests/Dumper/StateMachineGraphvizDumperTest.php index 6d79e83db8..0507b70ae1 100644 --- a/src/Symfony/Component/Workflow/Tests/Dumper/StateMachineGraphvizDumperTest.php +++ b/src/Symfony/Component/Workflow/Tests/Dumper/StateMachineGraphvizDumperTest.php @@ -30,13 +30,13 @@ digraph workflow { 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_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_86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 -> place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [label="t1" style="solid"]; - place_3c363836cf4e16666669a25da280a1865c2d2874 -> place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [label="t1" style="solid"]; - place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 -> place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [label="t2" style="solid"]; + place_3c363836cf4e16666669a25da280a1865c2d2874 -> place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [label="My custom transition label 3" style="solid" fontcolor="Grey" color="Red"]; + place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 -> place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [label="t2" style="solid" color="Blue"]; place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 -> place_3c363836cf4e16666669a25da280a1865c2d2874 [label="t3" style="solid"]; } @@ -56,13 +56,13 @@ digraph workflow { 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_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_86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 -> place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [label="t1" style="solid"]; - place_3c363836cf4e16666669a25da280a1865c2d2874 -> place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [label="t1" style="solid"]; - place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 -> place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [label="t2" style="solid"]; + place_3c363836cf4e16666669a25da280a1865c2d2874 -> place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 [label="My custom transition label 3" style="solid" fontcolor="Grey" color="Red"]; + place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 -> place_84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 [label="t2" style="solid" color="Blue"]; place_e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 -> place_3c363836cf4e16666669a25da280a1865c2d2874 [label="t3" style="solid"]; } diff --git a/src/Symfony/Component/Workflow/Tests/WorkflowBuilderTrait.php b/src/Symfony/Component/Workflow/Tests/WorkflowBuilderTrait.php index b9d58e4670..12c8f745e0 100644 --- a/src/Symfony/Component/Workflow/Tests/WorkflowBuilderTrait.php +++ b/src/Symfony/Component/Workflow/Tests/WorkflowBuilderTrait.php @@ -3,6 +3,7 @@ namespace Symfony\Component\Workflow\Tests; use Symfony\Component\Workflow\Definition; +use Symfony\Component\Workflow\Metadata\InMemoryMetadataStore; use Symfony\Component\Workflow\Transition; trait WorkflowBuilderTrait @@ -14,12 +15,21 @@ trait WorkflowBuilderTrait $transitions = []; $transitions[] = new Transition('t1', 'a', ['b', 'c']); $transitions[] = new Transition('t2', ['b', 'c'], 'd'); - $transitions[] = new Transition('t3', 'd', 'e'); + $transitionWithMetadataDumpStyle = new Transition('t3', 'd', 'e'); + $transitions[] = $transitionWithMetadataDumpStyle; $transitions[] = new Transition('t4', 'd', 'f'); $transitions[] = new Transition('t5', 'e', 'g'); $transitions[] = new Transition('t6', 'f', 'g'); - return new Definition($places, $transitions); + $transitionsMetadata = new \SplObjectStorage(); + $transitionsMetadata[$transitionWithMetadataDumpStyle] = [ + 'label' => 'My custom transition label 1', + 'color' => 'Red', + 'arrow_color' => 'Green', + ]; + $inMemoryMetadataStore = new InMemoryMetadataStore([], [], $transitionsMetadata); + + return new Definition($places, $transitions, null, $inMemoryMetadataStore); // The graph looks like: // +---+ +----+ +---+ +----+ +----+ +----+ +----+ +----+ +---+ @@ -38,10 +48,28 @@ trait WorkflowBuilderTrait $places = range('a', 'c'); $transitions = []; - $transitions[] = new Transition('t1', 'a', 'b'); - $transitions[] = new Transition('t2', 'b', 'c'); + $transitionWithMetadataDumpStyle = new Transition('t1', 'a', 'b'); + $transitions[] = $transitionWithMetadataDumpStyle; + $transitionWithMetadataArrowColorPink = new Transition('t2', 'b', 'c'); + $transitions[] = $transitionWithMetadataArrowColorPink; - return new Definition($places, $transitions); + $placesMetadata = []; + $placesMetadata['c'] = [ + 'bg_color' => 'DeepSkyBlue', + ]; + + $transitionsMetadata = new \SplObjectStorage(); + $transitionsMetadata[$transitionWithMetadataDumpStyle] = [ + 'label' => 'My custom transition label 2', + 'color' => 'Grey', + 'arrow_color' => 'Purple', + ]; + $transitionsMetadata[$transitionWithMetadataArrowColorPink] = [ + 'arrow_color' => 'Pink', + ]; + $inMemoryMetadataStore = new InMemoryMetadataStore([], $placesMetadata, $transitionsMetadata); + + return new Definition($places, $transitions, null, $inMemoryMetadataStore); // The graph looks like: // +---+ +----+ +---+ +----+ +---+ @@ -82,13 +110,24 @@ trait WorkflowBuilderTrait $places = ['a', 'b', 'c', 'd']; $transitions[] = new Transition('t1', 'a', 'b'); - $transitions[] = new Transition('t1', 'd', 'b'); - $transitions[] = new Transition('t2', 'b', 'c'); + $transitionWithMetadataDumpStyle = new Transition('t1', 'd', 'b'); + $transitions[] = $transitionWithMetadataDumpStyle; + $transitionWithMetadataArrowColorBlue = new Transition('t2', 'b', 'c'); + $transitions[] = $transitionWithMetadataArrowColorBlue; $transitions[] = new Transition('t3', 'b', 'd'); - $definition = new Definition($places, $transitions); + $transitionsMetadata = new \SplObjectStorage(); + $transitionsMetadata[$transitionWithMetadataDumpStyle] = [ + 'label' => 'My custom transition label 3', + 'color' => 'Grey', + 'arrow_color' => 'Red', + ]; + $transitionsMetadata[$transitionWithMetadataArrowColorBlue] = [ + 'arrow_color' => 'Blue', + ]; + $inMemoryMetadataStore = new InMemoryMetadataStore([], [], $transitionsMetadata); - return $definition; + return new Definition($places, $transitions, null, $inMemoryMetadataStore); // The graph looks like: // t1 diff --git a/src/Symfony/Component/Workflow/Tests/fixtures/puml/arrow/complex-state-machine-marking.puml b/src/Symfony/Component/Workflow/Tests/fixtures/puml/arrow/complex-state-machine-marking.puml index 699548ef16..59f8309adf 100644 --- a/src/Symfony/Component/Workflow/Tests/fixtures/puml/arrow/complex-state-machine-marking.puml +++ b/src/Symfony/Component/Workflow/Tests/fixtures/puml/arrow/complex-state-machine-marking.puml @@ -15,7 +15,7 @@ state "b" state "c" <> state "d" "a" --> "b": "t1" -"d" --> "b": "t1" -"b" --> "c": "t2" +"d" -[#Red]-> "b": "My custom transition label 3" +"b" -[#Blue]-> "c": "t2" "b" --> "d": "t3" @enduml diff --git a/src/Symfony/Component/Workflow/Tests/fixtures/puml/arrow/complex-state-machine-nomarking.puml b/src/Symfony/Component/Workflow/Tests/fixtures/puml/arrow/complex-state-machine-nomarking.puml index eb91152a46..f3549c6d75 100644 --- a/src/Symfony/Component/Workflow/Tests/fixtures/puml/arrow/complex-state-machine-nomarking.puml +++ b/src/Symfony/Component/Workflow/Tests/fixtures/puml/arrow/complex-state-machine-nomarking.puml @@ -15,7 +15,7 @@ state "b" state "c" state "d" "a" --> "b": "t1" -"d" --> "b": "t1" -"b" --> "c": "t2" +"d" -[#Red]-> "b": "My custom transition label 3" +"b" -[#Blue]-> "c": "t2" "b" --> "d": "t3" @enduml diff --git a/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/complex-workflow-marking.puml b/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/complex-workflow-marking.puml index 0ae74a7c44..1886ada0a8 100644 --- a/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/complex-workflow-marking.puml +++ b/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/complex-workflow-marking.puml @@ -33,8 +33,8 @@ agent "t6" "b" --> "t2" "t2" --> "d" "c" --> "t2" -"d" --> "t3" -"t3" --> "e" +"d" -[#Green]-> "t3": "My custom transition label 1" +"t3" -[#Green]-> "e": "My custom transition label 1" "d" --> "t4" "t4" --> "f" "e" --> "t5" diff --git a/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/complex-workflow-nomarking.puml b/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/complex-workflow-nomarking.puml index db3c8bf208..4ad91d9268 100644 --- a/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/complex-workflow-nomarking.puml +++ b/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/complex-workflow-nomarking.puml @@ -33,8 +33,8 @@ agent "t6" "b" --> "t2" "t2" --> "d" "c" --> "t2" -"d" --> "t3" -"t3" --> "e" +"d" -[#Green]-> "t3": "My custom transition label 1" +"t3" -[#Green]-> "e": "My custom transition label 1" "d" --> "t4" "t4" --> "f" "e" --> "t5" diff --git a/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-marking.puml b/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-marking.puml index f81c44c5c2..a316b64253 100644 --- a/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-marking.puml +++ b/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-marking.puml @@ -9,6 +9,7 @@ skinparam state { BorderColor #3887C6 BorderColor<> Black FontColor<> White + BackgroundColor<> DeepSkyBlue } skinparam agent { BackgroundColor #ffffff @@ -16,11 +17,11 @@ skinparam agent { } state "a" <> state "b" <> -state "c" +state "c" <> agent "t1" agent "t2" -"a" --> "t1" -"t1" --> "b" -"b" --> "t2" -"t2" --> "c" +"a" -[#Purple]-> "t1": "My custom transition label 2" +"t1" -[#Purple]-> "b": "My custom transition label 2" +"b" -[#Pink]-> "t2" +"t2" -[#Pink]-> "c" @enduml diff --git a/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-nomarking.puml b/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-nomarking.puml index c677c24f89..348ff6476b 100644 --- a/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-nomarking.puml +++ b/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-nomarking.puml @@ -9,6 +9,7 @@ skinparam state { BorderColor #3887C6 BorderColor<> Black FontColor<> White + BackgroundColor<> DeepSkyBlue } skinparam agent { BackgroundColor #ffffff @@ -16,11 +17,11 @@ skinparam agent { } state "a" <> state "b" -state "c" +state "c" <> agent "t1" agent "t2" -"a" --> "t1" -"t1" --> "b" -"b" --> "t2" -"t2" --> "c" +"a" -[#Purple]-> "t1": "My custom transition label 2" +"t1" -[#Purple]-> "b": "My custom transition label 2" +"b" -[#Pink]-> "t2" +"t2" -[#Pink]-> "c" @enduml