@@ -44,23 +44,27 @@ class GraphvizDumper implements DumperInterface
44
44
*/
45
45
public function dump (Definition $ definition , Marking $ marking = null , array $ options = []): string
46
46
{
47
- $ places = $ this ->findPlaces ($ definition , $ marking );
48
- $ transitions = $ this ->findTransitions ($ definition );
47
+ $ withMetadata = $ options ['with-metadata ' ] ?? false ;
48
+
49
+ $ places = $ this ->findPlaces ($ definition , $ withMetadata , $ marking );
50
+ $ transitions = $ this ->findTransitions ($ definition , $ withMetadata );
49
51
$ edges = $ this ->findEdges ($ definition );
50
52
51
53
$ options = array_replace_recursive (self ::$ defaultOptions , $ options );
52
54
53
- return $ this ->startDot ($ options )
54
- .$ this ->addPlaces ($ places )
55
- .$ this ->addTransitions ($ transitions )
55
+ $ label = $ this ->formatLabel ($ definition , $ withMetadata , $ options );
56
+
57
+ return $ this ->startDot ($ options , $ label )
58
+ .$ this ->addPlaces ($ places , $ withMetadata )
59
+ .$ this ->addTransitions ($ transitions , $ withMetadata )
56
60
.$ this ->addEdges ($ edges )
57
61
.$ this ->endDot ();
58
62
}
59
63
60
64
/**
61
65
* @internal
62
66
*/
63
- protected function findPlaces (Definition $ definition , Marking $ marking = null ): array
67
+ protected function findPlaces (Definition $ definition , bool $ withMetadata , Marking $ marking = null ): array
64
68
{
65
69
$ workflowMetadata = $ definition ->getMetadataStore ();
66
70
@@ -80,9 +84,16 @@ protected function findPlaces(Definition $definition, Marking $marking = null):
80
84
$ attributes ['style ' ] = 'filled ' ;
81
85
$ attributes ['fillcolor ' ] = $ backgroundColor ;
82
86
}
87
+ if ($ withMetadata ) {
88
+ $ attributes ['metadata ' ] = $ workflowMetadata ->getPlaceMetadata ($ place );
89
+ }
83
90
$ label = $ workflowMetadata ->getMetadata ('label ' , $ place );
84
91
if (null !== $ label ) {
85
92
$ attributes ['name ' ] = $ label ;
93
+ if ($ withMetadata ) {
94
+ // Don't include label in metadata if already used as name
95
+ unset($ attributes ['metadata ' ]['label ' ]);
96
+ }
86
97
}
87
98
$ places [$ place ] = [
88
99
'attributes ' => $ attributes ,
@@ -95,7 +106,7 @@ protected function findPlaces(Definition $definition, Marking $marking = null):
95
106
/**
96
107
* @internal
97
108
*/
98
- protected function findTransitions (Definition $ definition ): array
109
+ protected function findTransitions (Definition $ definition, bool $ withMetadata ): array
99
110
{
100
111
$ workflowMetadata = $ definition ->getMetadataStore ();
101
112
@@ -111,9 +122,17 @@ protected function findTransitions(Definition $definition): array
111
122
}
112
123
$ name = $ workflowMetadata ->getMetadata ('label ' , $ transition ) ?? $ transition ->getName ();
113
124
125
+ if ($ withMetadata ) {
126
+ $ metadata = $ workflowMetadata ->getTransitionMetadata ($ transition );
127
+ unset($ metadata ['label ' ]);
128
+ } else {
129
+ $ metadata = [];
130
+ }
131
+
114
132
$ transitions [] = [
115
133
'attributes ' => $ attributes ,
116
134
'name ' => $ name ,
135
+ 'metadata ' => $ metadata ,
117
136
];
118
137
}
119
138
@@ -123,7 +142,7 @@ protected function findTransitions(Definition $definition): array
123
142
/**
124
143
* @internal
125
144
*/
126
- protected function addPlaces (array $ places ): string
145
+ protected function addPlaces (array $ places, float $ withMetadata ): string
127
146
{
128
147
$ code = '' ;
129
148
@@ -135,7 +154,15 @@ protected function addPlaces(array $places): string
135
154
$ placeName = $ id ;
136
155
}
137
156
138
- $ code .= sprintf (" place_%s [label= \"%s \", shape=circle%s]; \n" , $ this ->dotize ($ id ), $ this ->escape ($ placeName ), $ this ->addAttributes ($ place ['attributes ' ]));
157
+ if ($ withMetadata ) {
158
+ $ escapedLabel = sprintf ('<<B>%s</B>%s> ' , $ this ->escape ($ placeName ), $ this ->addMetadata ($ place ['attributes ' ]['metadata ' ]));
159
+ // Don't include metadata in default attributes used to format the place
160
+ unset($ place ['attributes ' ]['metadata ' ]);
161
+ } else {
162
+ $ escapedLabel = sprintf ('"%s" ' , $ this ->escape ($ placeName ));
163
+ }
164
+
165
+ $ code .= sprintf (" place_%s [label=%s, shape=circle%s]; \n" , $ this ->dotize ($ id ), $ escapedLabel , $ this ->addAttributes ($ place ['attributes ' ]));
139
166
}
140
167
141
168
return $ code ;
@@ -144,12 +171,18 @@ protected function addPlaces(array $places): string
144
171
/**
145
172
* @internal
146
173
*/
147
- protected function addTransitions (array $ transitions ): string
174
+ protected function addTransitions (array $ transitions, bool $ withMetadata ): string
148
175
{
149
176
$ code = '' ;
150
177
151
178
foreach ($ transitions as $ i => $ place ) {
152
- $ code .= sprintf (" transition_%s [label= \"%s \",%s]; \n" , $ this ->dotize ($ i ), $ this ->escape ($ place ['name ' ]), $ this ->addAttributes ($ place ['attributes ' ]));
179
+ if ($ withMetadata ) {
180
+ $ escapedLabel = sprintf ('<<B>%s</B>%s> ' , $ this ->escape ($ place ['name ' ]), $ this ->addMetadata ($ place ['metadata ' ]));
181
+ } else {
182
+ $ escapedLabel = '" ' .$ this ->escape ($ place ['name ' ]).'" ' ;
183
+ }
184
+
185
+ $ code .= sprintf (" transition_%s [label=%s,%s]; \n" , $ this ->dotize ($ i ), $ escapedLabel , $ this ->addAttributes ($ place ['attributes ' ]));
153
186
}
154
187
155
188
return $ code ;
@@ -215,10 +248,11 @@ protected function addEdges(array $edges): string
215
248
/**
216
249
* @internal
217
250
*/
218
- protected function startDot (array $ options ): string
251
+ protected function startDot (array $ options, string $ label ): string
219
252
{
220
- return sprintf ("digraph workflow { \n %s \n node [%s]; \n edge [%s]; \n\n" ,
253
+ return sprintf ("digraph workflow { \n %s%s \n node [%s]; \n edge [%s]; \n\n" ,
221
254
$ this ->addOptions ($ options ['graph ' ]),
255
+ '"" ' !== $ label && '<> ' !== $ label ? sprintf (' label=%s ' , $ label ) : '' ,
222
256
$ this ->addOptions ($ options ['node ' ]),
223
257
$ this ->addOptions ($ options ['edge ' ])
224
258
);
@@ -248,6 +282,9 @@ protected function escape(string|bool $value): string
248
282
return \is_bool ($ value ) ? ($ value ? '1 ' : '0 ' ) : addslashes ($ value );
249
283
}
250
284
285
+ /**
286
+ * @internal
287
+ */
251
288
protected function addAttributes (array $ attributes ): string
252
289
{
253
290
$ code = [];
@@ -259,6 +296,34 @@ protected function addAttributes(array $attributes): string
259
296
return $ code ? ' ' .implode (' ' , $ code ) : '' ;
260
297
}
261
298
299
+
300
+ /**
301
+ * Handles the label of the graph depending on whether a label was set in CLI,
302
+ * if metadata should be included and if there are any.
303
+ *
304
+ * The produced label must be escaped.
305
+ *
306
+ * @internal
307
+ */
308
+ protected function formatLabel (Definition $ definition , string $ withMetadata , array $ options ): string
309
+ {
310
+ $ currentLabel = $ options ['label ' ] ?? '' ;
311
+
312
+ if (!$ withMetadata ) {
313
+ // Only currentLabel to handle. If null, will be translated to empty string
314
+ return sprintf ('"%s" ' , $ this ->escape ($ currentLabel ));
315
+ }
316
+ $ workflowMetadata = $ definition ->getMetadataStore ()->getWorkflowMetadata ();
317
+
318
+ if ('' === $ currentLabel ) {
319
+ // Only metadata to handle
320
+ return sprintf ('<%s> ' , $ this ->addMetadata ($ workflowMetadata , false ));
321
+ }
322
+
323
+ // currentLabel and metadata to handle
324
+ return sprintf ('<<B>%s</B>%s> ' , $ this ->escape ($ currentLabel ), $ this ->addMetadata ($ workflowMetadata ));
325
+ }
326
+
262
327
private function addOptions (array $ options ): string
263
328
{
264
329
$ code = [];
@@ -269,4 +334,25 @@ private function addOptions(array $options): string
269
334
270
335
return implode (' ' , $ code );
271
336
}
337
+
338
+ /**
339
+ * @param bool $lineBreakFirstIfNotEmpty Whether to add a separator in the first place when metadata is not empty
340
+ */
341
+ private function addMetadata (array $ metadata , bool $ lineBreakFirstIfNotEmpty = true ): string
342
+ {
343
+ $ code = [];
344
+
345
+ $ skipSeparator = !$ lineBreakFirstIfNotEmpty ;
346
+
347
+ foreach ($ metadata as $ key => $ value ) {
348
+ if ($ skipSeparator ) {
349
+ $ code [] = sprintf ('%s: %s ' , $ this ->escape ($ key ), $ this ->escape ($ value ));
350
+ $ skipSeparator = false ;
351
+ } else {
352
+ $ code [] = sprintf ('%s%s: %s ' , '<BR/> ' , $ this ->escape ($ key ), $ this ->escape ($ value ));
353
+ }
354
+ }
355
+
356
+ return $ code ? implode ('' , $ code ) : '' ;
357
+ }
272
358
}
0 commit comments