@@ -44,23 +44,27 @@ class GraphvizDumper implements DumperInterface
4444 */
4545 public function dump (Definition $ definition , Marking $ marking = null , array $ options = []): string
4646 {
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 );
4951 $ edges = $ this ->findEdges ($ definition );
5052
5153 $ options = array_replace_recursive (self ::$ defaultOptions , $ options );
5254
53- return $ this ->startDot ($ options )
54- .$ this ->addPlaces ($ places )
55- .$ this ->addTransitions ($ transitions )
55+ $ label = $ this ->formatLabel ($ d
3942
efinition , $ withMetadata , $ options );
56+
57+ return $ this ->startDot ($ options , $ label )
58+ .$ this ->addPlaces ($ places , $ withMetadata )
59+ .$ this ->addTransitions ($ transitions , $ withMetadata )
5660 .$ this ->addEdges ($ edges )
5761 .$ this ->endDot ();
5862 }
5963
6064 /**
6165 * @internal
6266 */
63- protected function findPlaces (Definition $ definition , Marking $ marking = null ): array
67+ protected function findPlaces (Definition $ definition , bool $ withMetadata , Marking $ marking = null ): array
6468 {
6569 $ workflowMetadata = $ definition ->getMetadataStore ();
6670
@@ -80,9 +84,16 @@ protected function findPlaces(Definition $definition, Marking $marking = null):
8084 $ attributes ['style ' ] = 'filled ' ;
8185 $ attributes ['fillcolor ' ] = $ backgroundColor ;
8286 }
87+ if ($ withMetadata ) {
88+ $ attributes ['metadata ' ] = $ workflowMetadata ->getPlaceMetadata ($ place );
89+ }
8390 $ label = $ workflowMetadata ->getMetadata ('label ' , $ place );
8491 if (null !== $ label ) {
8592 $ attributes ['name ' ] = $ label ;
93+ if ($ withMetadata ) {
94+ // Don't include label in metadata if already used as name
95+ unset($ attributes ['metadata ' ]['label ' ]);
96+ }
8697 }
8798 $ places [$ place ] = [
8899 'attributes ' => $ attributes ,
@@ -95,7 +106,7 @@ protected function findPlaces(Definition $definition, Marking $marking = null):
95106 /**
96107 * @internal
97108 */
98- protected function findTransitions (Definition $ definition ): array
109+ protected function findTransitions (Definition $ definition, bool $ withMetadata ): array
99110 {
100111 $ workflowMetadata = $ definition ->getMetadataStore ();
101112
@@ -111,9 +122,17 @@ protected function findTransitions(Definition $definition): array
111122 }
112123 $ name = $ workflowMetadata ->getMetadata ('label ' , $ transition ) ?? $ transition ->getName ();
113124
125+ if ($ withMetadata ) {
126+ $ metadata = $ workflowMetadata ->getTransitionMetadata ($ transition );
127+ unset($ metadata ['label ' ]);
128+ } else {
129+ $ metadata = [];
130+ }
131+
114132 $ transitions [] = [
115133 'attributes ' => $ attributes ,
116134 'name ' => $ name ,
135+ 'metadata ' => $ metadata ,
117136 ];
118137 }
119138
@@ -123,7 +142,7 @@ protected function findTransitions(Definition $definition): array
123142 /**
124143 * @internal
125144 */
126- protected function addPlaces (array $ places ): string
145+ protected function addPlaces (array $ places, float $ withMetadata ): string
127146 {
128147 $ code = '' ;
129148
@@ -135,7 +154,15 @@ protected function addPlaces(array $places): string
135154 $ placeName = $ id ;
136155 }
137156
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 ' ]));
139166 }
140167
141168 return $ code ;
@@ -144,12 +171,18 @@ protected function addPlaces(array $places): string
144171 /**
145172 * @internal
146173 */
147- protected function addTransitions (array $ transitions ): string
174+ protected function addTransitions (array $ transitions, bool $ withMetadata ): string
148175 {
149176
3942
$ code = '' ;
150177
151178 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 ' ]));
153186 }
154187
155188 return $ code ;
@@ -215,10 +248,11 @@ protected function addEdges(array $edges): string
215248 /**
216249 * @internal
217250 */
218- protected function startDot (array $ options ): string
251+ protected function startDot (array $ options, string $ label ): string
219252 {
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" ,
221254 $ this ->addOptions ($ options ['graph ' ]),
255+ '"" ' !== $ label && '<> ' !== $ label ? sprintf (' label=%s ' , $ label ) : '' ,
222256 $ this ->addOptions ($ options ['node ' ]),
223257 $ this ->addOptions ($ options ['edge ' ])
224258 );
@@ -248,6 +282,9 @@ protected function escape(string|bool $value): string
248282 return \is_bool ($ value ) ? ($ value ? '1 ' : '0 ' ) : addslashes ($ value );
249283 }
250284
285+ /**
286+ * @internal
287+ */
251288 protected function addAttributes (array $ attributes ): string
252289 {
253290 $ code = [];
@@ -259,6 +296,34 @@ protected function addAttributes(array $attributes): string
259296 return $ code ? ' ' .implode (' ' , $ code ) : '' ;
260297 }
261298
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+
262327 private function addOptions (array $ options ): string
263328 {
264329 $ code = [];
@@ -269,4 +334,25 @@ private function addOptions(array $options): string
269334
270335 return implode (' ' , $ code );
271336 }
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+ }
272358}
0 commit comments