Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 60ad109

Browse filesBrowse files
alexislefebvrefabpot
authored andcommitted
[Workflow] Add colors to workflow dumps
1 parent 50ff35f commit 60ad109
Copy full SHA for 60ad109

13 files changed

+288
-88
lines changed

‎src/Symfony/Component/Workflow/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Workflow/CHANGELOG.md
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,19 @@ CHANGELOG
66

77
* Trigger `entered` event for subject entering in the Workflow for the first time
88
* Added a context to `Workflow::apply()`. The `MethodMarkingStore` could be used to leverage this feature.
9+
* Add style to transitions by declaring metadata:
10+
```
11+
$places = range('a', 'b');
12+
$transition = new Transition('t1', 'a', 'b');
13+
$transitions[] = $transition;
14+
$transitionsMetadata = new \SplObjectStorage();
15+
$transitionsMetadata[$transition] = [
16+
'color' => 'Red',
17+
'arrow_color' => '#00ff00',
18+
];
19+
$inMemoryMetadataStore = new InMemoryMetadataStore([], [], $transitionsMetadata);
20+
return new Definition($places, $transitions, null, $inMemoryMetadataStore);
21+
```
922

1023
4.1.0
1124
-----

‎src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php
+41-8Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ public function dump(Definition $definition, Marking $marking = null, array $opt
6363
*/
6464
protected function findPlaces(Definition $definition, Marking $marking = null)
6565
{
66+
$workflowMetadata = $definition->getMetadataStore();
67+
6668
$places = [];
6769

6870
foreach ($definition->getPlaces() as $place) {
@@ -74,6 +76,15 @@ protected function findPlaces(Definition $definition, Marking $marking = null)
7476
$attributes['color'] = '#FF0000';
7577
$attributes['shape'] = 'doublecircle';
7678
}
79+
$backgroundColor = $workflowMetadata->getMetadata('bg_color', $place);
80+
if (null !== $backgroundColor) {
81+
$attributes['style'] = 'filled';
82+
$attributes['fillcolor'] = $backgroundColor;
83+
}
84+
$label = $workflowMetadata->getMetadata('label', $place);
85+
if (null !== $label) {
86+
$attributes['name'] = $label;
87+
}
7788
$places[$place] = [
7889
'attributes' => $attributes,
7990
];
@@ -87,12 +98,23 @@ protected function findPlaces(Definition $definition, Marking $marking = null)
8798
*/
8899
protected function findTransitions(Definition $definition)
89100
{
101+
$workflowMetadata = $definition->getMetadataStore();
102+
90103
$transitions = [];
91104

92105
foreach ($definition->getTransitions() as $transition) {
106+
$attributes = ['shape' => 'box', 'regular' => true];
107+
108+
$backgroundColor = $workflowMetadata->getMetadata('bg_color', $transition);
109+
if (null !== $backgroundColor) {
110+
$attributes['style'] = 'filled';
111+
$attributes['fillcolor'] = $backgroundColor;
112+
}
113+
$name = $workflowMetadata->getMetadata('label', $transition) ?? $transition->getName();
114+
93115
$transitions[] = [
94-
'attributes' => ['shape' => 'box', 'regular' => true],
95-
'name' => $transition->getName(),
116+
'attributes' => $attributes,
117+
'name' => $name,
96118
];
97119
}
98120

@@ -107,7 +129,14 @@ protected function addPlaces(array $places)
107129
$code = '';
108130

109131
foreach ($places as $id => $place) {
110-
$code .= sprintf(" place_%s [label=\"%s\", shape=circle%s];\n", $this->dotize($id), $this->escape($id), $this->addAttributes($place['attributes']));
132+
if (isset($place['attributes']['name'])) {
133+
$placeName = $place['attributes']['name'];
134+
unset($place['attributes']['name']);
135+
} else {
136+
$placeName = $id;
137+
}
138+
139+
$code .= sprintf(" place_%s [label=\"%s\", shape=circle%s];\n", $this->dotize($id), $this->escape($placeName), $this->addAttributes($place['attributes']));
111140
}
112141

113142
return $code;
@@ -121,7 +150,7 @@ protected function addTransitions(array $transitions)
121150
$code = '';
122151

123152
foreach ($transitions as $place) {
124-
$code .= sprintf(" transition_%s [label=\"%s\", shape=box%s];\n", $this->dotize($place['name']), $this->escape($place['name']), $this->addAttributes($place['attributes']));
153+
$code .= sprintf(" transition_%s [label=\"%s\",%s];\n", $this->dotize($place['name']), $this->escape($place['name']), $this->addAttributes($place['attributes']));
125154
}
126155

127156
return $code;
@@ -132,19 +161,23 @@ protected function addTransitions(array $transitions)
132161
*/
133162
protected function findEdges(Definition $definition)
134163
{
164+
$workflowMetadata = $definition->getMetadataStore();
165+
135166
$dotEdges = [];
136167

137168
foreach ($definition->getTransitions() as $transition) {
169+
$transitionName = $workflowMetadata->getMetadata('label', $transition) ?? $transition->getName();
170+
138171
foreach ($transition->getFroms() as $from) {
139172
$dotEdges[] = [
140173
'from' => $from,
141-
'to' => $transition->getName(),
174+
'to' => $transitionName,
142175
'direction' => 'from',
143176
];
144177
}
145178
foreach ($transition->getTos() as $to) {
146179
$dotEdges[] = [
147-
'from' => $transition->getName(),
180+
'from' => $transitionName,
148181
'to' => $to,
149182
'direction' => 'to',
150183
];
@@ -209,15 +242,15 @@ protected function escape($value): string
209242
return \is_bool($value) ? ($value ? '1' : '0') : \addslashes($value);
210243
}
211244

212-
private function addAttributes(array $attributes): string
245+
protected function addAttributes(array $attributes): string
213246
{
214247
$code = [];
215248

216249
foreach ($attributes as $k => $v) {
217250
$code[] = sprintf('%s="%s"', $k, $this->escape($v));
218251
}
219252

220-
return $code ? ', '.implode(', ', $code) : '';
253+
return $code ? ' '.implode(' ', $code) : '';
221254
}
222255

223256
private function addOptions(array $options): string

‎src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php
+99-10Lines changed: 99 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
use InvalidArgumentException;
1515
use Symfony\Component\Workflow\Definition;
1616
use Symfony\Component\Workflow\Marking;
17+
use Symfony\Component\Workflow\Metadata\MetadataStoreInterface;
18+
use Symfony\Component\Workflow\Transition;
1719

1820
/**
1921
* PlantUmlDumper dumps a workflow as a PlantUML file.
@@ -63,13 +65,13 @@ public function __construct(string $transitionType = null)
6365
public function dump(Definition $definition, Marking $marking = null, array $options = []): string
6466
{
6567
$options = array_replace_recursive(self::DEFAULT_OPTIONS, $options);
66-
$code = $this->initialize($options);
68+
69+
$workflowMetadata = $definition->getMetadataStore();
70+
71+
$code = $this->initialize($options, $definition);
72+
6773
foreach ($definition->getPlaces() as $place) {
68-
$placeEscaped = $this->escape($place);
69-
$code[] =
70-
"state $placeEscaped".
71-
($definition->getInitialPlace() === $place ? ' '.self::INITIAL : '').
72-
($marking && $marking->has($place) ? ' '.self::MARKED : '');
74+
$code[] = $this->getState($place, $definition, $marking);
7375
}
7476
if ($this->isWorkflowTransitionType()) {
7577
foreach ($definition->getTransitions() as $transition) {
@@ -83,18 +85,34 @@ public function dump(Definition $definition, Marking $marking = null, array $opt
8385
$fromEscaped = $this->escape($from);
8486
foreach ($transition->getTos() as $to) {
8587
$toEscaped = $this->escape($to);
88+
89+
$transitionEscapedWithStyle = $this->getTransitionEscapedWithStyle($workflowMetadata, $transition, $transitionEscaped);
90+
91+
$arrowColor = $workflowMetadata->getMetadata('arrow_color', $transition);
92+
93+
$transitionColor = '';
94+
if (null !== $arrowColor) {
95+
$transitionColor = $this->getTransitionColor($arrowColor) ?? '';
96+
}
97+
8698
if ($this->isWorkflowTransitionType()) {
99+
$transitionLabel = '';
100+
// Add label only if it has a style
101+
if ($transitionEscapedWithStyle != $transitionEscaped) {
102+
$transitionLabel = ": $transitionEscapedWithStyle";
103+
}
104+
87105
$lines = [
88-
"$fromEscaped --> $transitionEscaped",
89-
"$transitionEscaped --> $toEscaped",
106+
"$fromEscaped -${transitionColor}-> ${transitionEscaped}${transitionLabel}",
107+
"$transitionEscaped -${transitionColor}-> ${toEscaped}${transitionLabel}",
90108
];
91109
foreach ($lines as $line) {
92110
if (!\in_array($line, $code)) {
93111
$code[] = $line;
94112
}
95113
}
96114
} else {
97-
$code[] = "$fromEscaped --> $toEscaped: $transitionEscaped";
115+
$code[] = "$fromEscaped -${transitionColor}-> $toEscaped: $transitionEscapedWithStyle";
98116
}
99117
}
100118
}
@@ -126,15 +144,28 @@ private function getLines(array $code): string
126144
return implode(PHP_EOL, $code);
127145
}
128146

129-
private function initialize(array $options): array
147+
private function initialize(array $options, Definition $definition): array
130148
{
149+
$workflowMetadata = $definition->getMetadataStore();
150+
131151
$code = [];
132152
if (isset($options['title'])) {
133153
$code[] = "title {$options['title']}";
134154
}
135155
if (isset($options['name'])) {
136156
$code[] = "title {$options['name']}";
137157
}
158+
159+
// Add style from nodes
160+
foreach ($definition->getPlaces() as $place) {
161+
$backgroundColor = $workflowMetadata->getMetadata('bg_color', $place);
162+
if (null !== $backgroundColor) {
163+
$key = 'BackgroundColor<<'.$this->getColorId($backgroundColor).'>>';
164+
165+
$options['skinparams']['state'][$key] = $backgroundColor;
166+
}
167+
}
168+
138169
if (isset($options['skinparams']) && \is_array($options['skinparams'])) {
139170
foreach ($options['skinparams'] as $skinparamKey => $skinparamValue) {
140171
if (!$this->isWorkflowTransitionType() && 'agent' === $skinparamKey) {
@@ -160,4 +191,62 @@ private function escape(string $string): string
160191
// It's not possible to escape property double quote, so let's remove it
161192
return '"'.str_replace('"', '', $string).'"';
162193
}
194+
195+
private function getState(string $place, Definition $definition, Marking $marking = null): string
196+
{
197+
$workflowMetadata = $definition->getMetadataStore();
198+
199+
$placeEscaped = $this->escape($place);
200+
201+
$output = "state $placeEscaped".
202+
($definition->getInitialPlace() === $place ? ' '.self::INITIAL : '').
203+
($marking && $marking->has($place) ? ' '.self::MARKED : '');
204+
205+
$backgroundColor = $workflowMetadata->getMetadata('bg_color', $place);
206+
if (null !== $backgroundColor) {
207+
$output .= ' <<'.$this->getColorId($backgroundColor).'>>';
208+
}
209+
210+
$description = $workflowMetadata->getMetadata('description', $place);
211+
if (null !== $description) {
212+
$output .= ' as '.$place.
213+
PHP_EOL.
214+
$place.' : '.$description;
215+
}
216+
217+
return $output;
218+
}
219+
220+
private function getTransitionEscapedWithStyle(MetadataStoreInterface $workflowMetadata, Transition $transition, string $to): string
221+
{
222+
$to = $workflowMetadata->getMetadata('label', $transition) ?? $to;
223+
224+
$color = $workflowMetadata->getMetadata('color', $transition) ?? null;
225+
226+
if (null !== $color) {
227+
$to = sprintf(
228+
'<font color=%1$s>%2$s</font>',
229+
$color,
230+
$to
231+
);
232+
}
233+
234+
return $this->escape($to);
235+
}
236+
237+
private function getTransitionColor(string $color): string
238+
{
239+
// PUML format requires that color in transition have to be prefixed with “#”.
240+
if ('#' !== substr($color, 0, 1)) {
241+
$color = '#'.$color;
242+
}
243+
244+
return sprintf('[%s]', $color);
245+
}
246+
247+
private function getColorId(string $color): string
248+
{
249+
// Remove “#“ from start of the color name so it can be used as an identifier.
250+
return ltrim($color, '#');
251+
}
163252
}

‎src/Symfony/Component/Workflow/Dumper/StateMachineGraphvizDumper.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Workflow/Dumper/StateMachineGraphvizDumper.php
+27-3Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,32 @@ public function dump(Definition $definition, Marking $marking = null, array $opt
4646
*/
4747
protected function findEdges(Definition $definition)
4848
{
49+
$workflowMetadata = $definition->getMetadataStore();
50+
4951
$edges = [];
5052

5153
foreach ($definition->getTransitions() as $transition) {
54+
$attributes = [];
55+
56+
$transitionName = $workflowMetadata->getMetadata('label', $transition) ?? $transition->getName();
57+
58+
$labelColor = $workflowMetadata->getMetadata('color', $transition);
59+
if (null !== $labelColor) {
60+
$attributes['fontcolor'] = $labelColor;
61+
}
62+
$arrowColor = $workflowMetadata->getMetadata('arrow_color', $transition);
63+
if (null !== $arrowColor) {
64+
$attributes['color'] = $arrowColor;
65+
}
66+
5267
foreach ($transition->getFroms() as $from) {
5368
foreach ($transition->getTos() as $to) {
54-
$edges[$from][] = [
55-
'name' => $transition->getName(),
69+
$edge = [
70+
'name' => $transitionName,
5671
'to' => $to,
72+
'attributes' => $attributes,
5773
];
74+
$edges[$from][] = $edge;
5875
}
5976
}
6077
}
@@ -71,7 +88,14 @@ protected function addEdges(array $edges)
7188

7289
foreach ($edges as $id => $edges) {
7390
foreach ($edges as $edge) {
74-
$code .= sprintf(" place_%s -> place_%s [label=\"%s\" style=\"%s\"];\n", $this->dotize($id), $this->dotize($edge['to']), $this->escape($edge['name']), 'solid');
91+
$code .= sprintf(
92+
" place_%s -> place_%s [label=\"%s\" style=\"%s\"%s];\n",
93+
$this->dotize($id),
94+
$this->dotize($edge['to']),
95+
$this->escape($edge['name']),
96+
'solid',
97+
$this->addAttributes($edge['attributes'])
98+
);
7599
}
76100
}
77101

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.