Skip to content
  • About
    • What is Symfony?
    • Community
    • News
    • Contributing
    • Support
  • Documentation
    • Symfony Docs
    • Symfony Book
    • Screencasts
    • Symfony Bundles
    • Symfony Cloud
    • Training
  • Services
    • Platform.sh for Symfony Best platform to deploy Symfony apps
    • SymfonyInsight Automatic quality checks for your apps
    • Symfony Certification Prove your knowledge and boost your career
    • SensioLabs Professional services to help you with Symfony
    • Blackfire Profile and monitor performance of your apps
  • Other
  • Blog
  • Download
sponsored by
  1. Home
  2. Documentation
  3. Workflow
  4. How to Dump Workflows

How to Dump Workflows

Edit this page

To help you debug your workflows, you can generate a visual representation of them as SVG or PNG images. First, install any of these free and open source applications needed to generate the images:

  • Graphviz, provides the dot command;
  • Mermaid CLI, provides the mmdc command;
  • PlantUML, provides the plantuml.jar file (which requires Java).

If you are defining the workflow inside a Symfony application, run this command to dump it as an image:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# using Graphviz's 'dot' and SVG images
$ php bin/console workflow:dump workflow-name | dot -Tsvg -o graph.svg

# using Graphviz's 'dot' and PNG images
$ php bin/console workflow:dump workflow-name | dot -Tpng -o graph.png

# using PlantUML's 'plantuml.jar'
$ php bin/console workflow:dump workflow_name --dump-format=puml | java -jar plantuml.jar -p  > graph.png

# highlight 'place1' and 'place2' in the dumped workflow
$ php bin/console workflow:dump workflow-name place1 place2 | dot -Tsvg -o graph.svg

# using Mermaid.js CLI
$ php bin/console workflow:dump workflow_name --dump-format=mermaid | mmdc -o graph.svg

The DOT image will look like this:

A state diagram of the Symfony workflow created by DOT.

The Mermaid image will look like this:

A state diagram of the Symfony workflow created by Mermaid.

The PlantUML image will look like this:

A state diagram of the Symfony workflow created by PlantUML.

If you are creating workflows outside of a Symfony application, use the GraphvizDumper or StateMachineGraphvizDumper class to create the DOT files and PlantUmlDumper to create the PlantUML files:

1
2
3
4
5
6
7
// Add this code to a PHP script; for example: dump-graph.php
$dumper = new GraphvizDumper();
echo $dumper->dump($definition);

# if you prefer PlantUML, use this code:
# $dumper = new PlantUmlDumper();
# echo $dumper->dump($definition);
1
2
3
# replace 'dump-graph.php' by the name of your PHP script
$ php dump-graph.php | dot -Tsvg -o graph.svg
$ php dump-graph.php | java -jar plantuml.jar -p  > graph.png

Styling

You can use --with-metadata option in the workflow:dump command to include places, transitions and workflow's metadata.

The DOT image will look like this :

Note

The --with-metadata option only works for the DOT dumper for now.

Note

The label metadata is not included in the dumped metadata, because it is used as a place's title.

You can use metadata with the following keys to style the workflow:

  • for places:

    • bg_color: a color;
    • description: a string that describes the state.
  • for transitions:

    • label: a string that replaces the name of the transition;
    • color: a color;
    • arrow_color: a color.

Strings can include \n characters to display the contents in multiple lines. Colors can be defined as:

  • a color name from PlantUML's color list;
  • an hexadecimal color (both #AABBCC and #ABC formats are supported).

Note

The Mermaid dumper does not support coloring the arrow heads with arrow_color as there is no support in Mermaid for doing so.

Below is the configuration for the pull request state machine with styling added.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# config/packages/workflow.yaml
framework:
    workflows:
        pull_request:
            type: 'state_machine'
            marking_store:
                type: 'method'
                property: 'currentPlace'
            supports:
                - App\Entity\PullRequest
            initial_marking: start
            places:
                start: ~
                coding: ~
                test: ~
                review:
                    metadata:
                        description: Human review
                merged: ~
                closed:
                    metadata:
                        bg_color: DeepSkyBlue
            transitions:
                submit:
                    from: start
                    to: test
                update:
                    from: [coding, test, review]
                    to: test
                    metadata:
                        arrow_color: Turquoise
                wait_for_review:
                    from: test
                    to: review
                    metadata:
                        color: Orange
                request_change:
                    from: review
                    to: coding
                accept:
                    from: review
                    to: merged
                    metadata:
                        label: Accept PR
                reject:
                    from: review
                    to: closed
                reopen:
                    from: closed
                    to: review
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
<!-- config/packages/workflow.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:framework="http://symfony.com/schema/dic/symfony"
    xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"
>

    <framework:config>
        <framework:workflow name="pull_request" type="state_machine">
            <framework:marking-store>
                <framework:type>method</framework:type>
                <framework:property>currentPlace</framework:property>
            </framework:marking-store>

            <framework:support>App\Entity\PullRequest</framework:support>

            <framework:initial_marking>start</framework:initial_marking>

            <framework:place>start</framework:place>
            <framework:place>coding</framework:place>
            <framework:place>test</framework:place>
            <framework:place name="review">
                <framework:metadata>
                    <framework:description>Human review</framework:description>
                </framework:metadata>
            </framework:place>
            <framework:place>merged</framework:place>
            <framework:place name="closed">
                <framework:metadata>
                    <framework:bg_color>DeepSkyBlue</framework:bg_color>
                </framework:metadata>
            </framework:place>

            <framework:transition name="submit">
                <framework:from>start</framework:from>

                <framework:to>test</framework:to>
            </framework:transition>

            <framework:transition name="update">
                <framework:from>coding</framework:from>
                <framework:from>test</framework:from>
                <framework:from>review</framework:from>

                <framework:to>test</framework:to>

                <framework:metadata>
                    <framework:arrow_color>Turquoise</framework:arrow_color>
                </framework:metadata>
            </framework:transition>

            <framework:transition name="wait_for_review">
                <framework:from>test</framework:from>

                <framework:to>review</framework:to>

                <framework:metadata>
                    <framework:color>Orange</framework:color>
                </framework:metadata>
            </framework:transition>

            <framework:transition name="request_change">
                <framework:from>review</framework:from>

                <framework:to>coding</framework:to>
            </framework:transition>

            <framework:transition name="accept">
                <framework:from>review</framework:from>

                <framework:to>merged</framework:to>

                <framework:metadata>
                    <framework:label>Accept PR</framework:label>
                </framework:metadata>
            </framework:transition>

            <framework:transition name="reject">
                <framework:from>review</framework:from>

                <framework:to>closed</framework:to>
            </framework:transition>

            <framework:transition name="reopen">
                <framework:from>closed</framework:from>

                <framework:to>review</framework:to>
            </framework:transition>

        </framework:workflow>

    </framework:config>
</container>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// config/packages/workflow.php
use Symfony\Config\FrameworkConfig;

return static function (FrameworkConfig $framework): void {
    // ...
    $pullRequest = $framework->workflows()->workflows('pull_request');

    $pullRequest
        ->type('state_machine')
        ->supports(['App\Entity\PullRequest'])
        ->initialMarking(['start']);

    $pullRequest->markingStore()
        ->type('method')
        ->property('currentPlace');

    $pullRequest->place()->name('start');
    $pullRequest->place()->name('coding');
    $pullRequest->place()->name('test');
    $pullRequest->place()
        ->name('review')
        ->metadata(['description' => 'Human review']);
    $pullRequest->place()->name('merged');
    $pullRequest->place()
        ->name('closed')
        ->metadata(['bg_color' => 'DeepSkyBlue',]);

    $pullRequest->transition()
        ->name('submit')
            ->from(['start'])
            ->to(['test']);

    $pullRequest->transition()
        ->name('update')
            ->from(['coding', 'test', 'review'])
            ->to(['test'])
            ->metadata(['arrow_color' => 'Turquoise']);

    $pullRequest->transition()
        ->name('wait_for_review')
            ->from(['test'])
            ->to(['review'])
            ->metadata(['color' => 'Orange']);

    $pullRequest->transition()
        ->name('request_change')
            ->from(['review'])
            ->to(['coding']);

    $pullRequest->transition()
        ->name('accept')
            ->from(['review'])
            ->to(['merged'])
            ->metadata(['label' => 'Accept PR']);

    $pullRequest->transition()
        ->name('reject')
            ->from(['review'])
            ->to(['closed']);

    $pullRequest->transition()
        ->name('accept')
            ->from(['closed'])
            ->to(['review']);
};

The PlantUML image will look like this:

A state diagram created by PlantUML with custom transition colors and descriptions.
This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version

    Symfony 7.1 is backed by

    Check Code Performance in Dev, Test, Staging & Production

    Check Code Performance in Dev, Test, Staging & Production

    No stress: we've got you covered with our 116 automated quality checks of your code

    No stress: we've got you covered with our 116 automated quality checks of your code

    Version:
    • Styling

    Symfony footer

    Avatar of Silvio Ginter, a Symfony contributor

    Thanks Silvio Ginter for being a Symfony contributor

    1 commit • 136 lines changed

    View all contributors that help us make Symfony

    Become a Symfony contributor

    Be an active part of the community and contribute ideas, code and bug fixes. Both experts and newcomers are welcome.

    Learn how to contribute

    Symfony™ is a trademark of Symfony SAS. All rights reserved.

    • What is Symfony?

      • What is Symfony?
      • Symfony at a Glance
      • Symfony Components
      • Symfony Releases
      • Security Policy
      • Logo & Screenshots
      • Trademark & Licenses
      • symfony1 Legacy
    • Learn Symfony

      • Symfony Docs
      • Symfony Book
      • Reference
      • Bundles
      • Best Practices
      • Training
      • eLearning Platform
      • Certification
    • Screencasts

      • Learn Symfony
      • Learn PHP
      • Learn JavaScript
      • Learn Drupal
      • Learn RESTful APIs
    • Community

      • Symfony Community
      • SymfonyConnect
      • Events & Meetups
      • Projects using Symfony
      • Contributors
      • Symfony Jobs
      • Backers
      • Code of Conduct
      • Downloads Stats
      • Support
    • Blog

      • All Blog Posts
      • A Week of Symfony
      • Case Studies
      • Cloud
      • Community
      • Conferences
      • Diversity
      • Living on the edge
      • Releases
      • Security Advisories
      • Symfony Insight
      • Twig
      • SensioLabs Blog
    • Services

      • SensioLabs services
      • Train developers
      • Manage your project quality
      • Improve your project performance
      • Host Symfony projects

      Powered by

    Follow Symfony