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 6e0b6ea

Browse filesBrowse files
committed
bug #20583 [Workflow] Fixed graphviz dumper for state machine (lyrixx)
This PR was merged into the 3.3-dev branch. Discussion ---------- [Workflow] Fixed graphviz dumper for state machine | Q | A | ------------- | --- | Branch? | master | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #20497 | License | MIT | Doc PR | ~ --- Before: ![before](https://cloud.githubusercontent.com/assets/408368/20490801/77cc0abe-b00f-11e6-8094-f4d428d5acde.png) After: ![after](https://cloud.githubusercontent.com/assets/408368/20490809/7d21a4b0-b00f-11e6-8de2-c5021fe2d4e0.png) --- Script: ```php <?php require __DIR__.'/vendor/autoload.php'; use Symfony\Component\Workflow\Definition; use Symfony\Component\Workflow\Dumper\StateMachineGraphvizDumper; use Symfony\Component\Workflow\Marking; use Symfony\Component\Workflow\StateMachine; use Symfony\Component\Workflow\Transition; $places = array('a', 'b', 'c', 'd'); $transitions[] = new Transition('t1', 'a', 'b'); $transitions[] = new Transition('t1', 'd', 'b'); $transitions[] = new Transition('t2', 'b', 'c'); $transitions[] = new Transition('t3', 'b', 'd'); $definition = new Definition($places, $transitions); $marking = new Marking(['d' => 1]); echo (new StateMachineGraphvizDumper())->dump($definition, $marking); ``` Commits ------- 1e92e02 [Workflow] Fixed graphviz dumper for state machine
2 parents 9361c5e + 1e92e02 commit 6e0b6ea
Copy full SHA for 6e0b6ea

File tree

9 files changed

+260
-86
lines changed
Filter options

9 files changed

+260
-86
lines changed

‎src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php
+3-1Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\Console\Input\InputInterface;
1616
use Symfony\Component\Console\Output\OutputInterface;
1717
use Symfony\Component\Workflow\Dumper\GraphvizDumper;
18+
use Symfony\Component\Workflow\Dumper\StateMachineGraphvizDumper;
1819
use Symfony\Component\Workflow\Marking;
1920
use Symfony\Component\Workflow\Workflow;
2021

@@ -60,13 +61,14 @@ protected function execute(InputInterface $input, OutputInterface $output)
6061
$serviceId = $input->getArgument('name');
6162
if ($container->has('workflow.'.$serviceId)) {
6263
$workflow = $container->get('workflow.'.$serviceId);
64+
$dumper = new GraphvizDumper();
6365
} elseif ($container->has('state_machine.'.$serviceId)) {
6466
$workflow = $container->get('state_machine.'.$serviceId);
67+
$dumper = new StateMachineGraphvizDumper();
6568
} else {
6669
throw new \InvalidArgumentException(sprintf('No service found for "workflow.%1$s" nor "state_machine.%1$s".', $serviceId));
6770
}
6871

69-
$dumper = new GraphvizDumper();
7072
$marking = new Marking();
7173

7274
foreach ($input->getArgument('marking') as $place) {

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php
+45-26Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
*/
2727
class GraphvizDumper implements DumperInterface
2828
{
29-
private static $defaultOptions = array(
29+
protected static $defaultOptions = array(
3030
'graph' => array('ratio' => 'compress', 'rankdir' => 'LR'),
3131
'node' => array('fontsize' => 9, 'fontname' => 'Arial', 'color' => '#333333', 'fillcolor' => 'lightblue', 'fixedsize' => true, 'width' => 1),
3232
'edge' => array('fontsize' => 9, 'fontname' => 'Arial', 'color' => '#333333', 'arrowhead' => 'normal', 'arrowsize' => 0.5),
@@ -58,7 +58,10 @@ public function dump(Definition $definition, Marking $marking = null, array $opt
5858
.$this->endDot();
5959
}
6060

61-
private function findPlaces(Definition $definition, Marking $marking = null)
61+
/**
62+
* @internal
63+
*/
64+
protected function findPlaces(Definition $definition, Marking $marking = null)
6265
{
6366
$places = array();
6467

@@ -79,7 +82,10 @@ private function findPlaces(Definition $definition, Marking $marking = null)
7982
return $places;
8083
}
8184

82-
private function findTransitions(Definition $definition)
85+
/**
86+
* @internal
87+
*/
88+
protected function findTransitions(Definition $definition)
8389
{
8490
$transitions = array();
8591

@@ -93,37 +99,38 @@ private function findTransitions(Definition $definition)
9399
return $transitions;
94100
}
95101

96-
private function addPlaces(array $places)
102+
/**
103+
* @internal
104+
*/
105+
protected function addPlaces(array $places)
97106
{
98107
$code = '';
99108

100109
foreach ($places as $id => $place) {
101-
$code .= sprintf(" place_%s [label=\"%s\", shape=circle%s];\n",
102-
$this->dotize($id),
103-
$id,
104-
$this->addAttributes($place['attributes'])
105-
);
110+
$code .= sprintf(" place_%s [label=\"%s\", shape=circle%s];\n", $this->dotize($id), $id, $this->addAttributes($place['attributes']));
106111
}
107112

108113
return $code;
109114
}
110115

111-
private function addTransitions(array $transitions)
116+
/**
117+
* @internal
118+
*/
119+
protected function addTransitions(array $transitions)
112120
{
113121
$code = '';
114122

115123
foreach ($transitions as $place) {
116-
$code .= sprintf(" transition_%s [label=\"%s\", shape=box%s];\n",
117-
$this->dotize($place['name']),
118-
$place['name'],
119-
$this->addAttributes($place['attributes'])
120-
);
124+
$code .= sprintf(" transition_%s [label=\"%s\", shape=box%s];\n", $this->dotize($place['name']), $place['name'], $this->addAttributes($place['attributes']));
121125
}
122126

123127
return $code;
124128
}
125129

126-
private function findEdges(Definition $definition)
130+
/**
131+
* @internal
132+
*/
133+
protected function findEdges(Definition $definition)
127134
{
128135
$dotEdges = array();
129136

@@ -147,7 +154,10 @@ private function findEdges(Definition $definition)
147154
return $dotEdges;
148155
}
149156

150-
private function addEdges($edges)
157+
/**
158+
* @internal
159+
*/
160+
protected function addEdges(array $edges)
151161
{
152162
$code = '';
153163

@@ -163,7 +173,10 @@ private function addEdges($edges)
163173
return $code;
164174
}
165175

166-
private function startDot(array $options)
176+
/**
177+
* @internal
178+
*/
179+
protected function startDot(array $options)
167180
{
168181
return sprintf("digraph workflow {\n %s\n node [%s];\n edge [%s];\n\n",
169182
$this->addOptions($options['graph']),
@@ -172,12 +185,23 @@ private function startDot(array $options)
172185
);
173186
}
174187

175-
private function endDot()
188+
/**
189+
* @internal
190+
*/
191+
protected function endDot()
176192
{
177193
return "}\n";
178194
}
179195

180-
private function addAttributes($attributes)
196+
/**
197+
* @internal
198+
*/
199+
protected function dotize($id)
200+
{
201+
return strtolower(preg_replace('/[^\w]/i', '_', $id));
202+
}
203+
204+
private function addAttributes(array $attributes)
181205
{
182206
$code = array();
183207

@@ -188,7 +212,7 @@ private function addAttributes($attributes)
188212
return $code ? ', '.implode(', ', $code) : '';
189213
}
190214

191-
private function addOptions($options)
215+
private function addOptions(array $options)
192216
{
193217
$code = array();
194218

@@ -198,9 +222,4 @@ private function addOptions($options)
198222

199223
return implode(' ', $code);
200224
}
201-
202-
private function dotize($id)
203-
{
204-
return strtolower(preg_replace('/[^\w]/i', '_', $id));
205-
}
206225
}
+80Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Workflow\Dumper;
13+
14+
use Symfony\Component\Workflow\Definition;
15+
use Symfony\Component\Workflow\Marking;
16+
17+
class StateMachineGraphvizDumper extends GraphvizDumper
18+
{
19+
/**
20+
* {@inheritdoc}
21+
*
22+
* Dumps the workflow as a graphviz graph.
23+
*
24+
* Available options:
25+
*
26+
* * graph: The default options for the whole graph
27+
* * node: The default options for nodes (places)
28+
* * edge: The default options for edges
29+
*/
30+
public function dump(Definition $definition, Marking $marking = null, array $options = array())
31+
{
32+
$places = $this->findPlaces($definition, $marking);
33+
$edges = $this->findEdges($definition);
34+
35+
$options = array_replace_recursive(self::$defaultOptions, $options);
36+
37+
return $this->startDot($options)
38+
.$this->addPlaces($places)
39+
.$this->addEdges($edges)
40+
.$this->endDot()
41+
;
42+
}
43+
44+
/**
45+
* @internal
46+
*/
47+
protected function findEdges(Definition $definition)
48+
{
49+
$edges = array();
50+
51+
foreach ($definition->getTransitions() as $transition) {
52+
foreach ($transition->getFroms() as $from) {
53+
foreach ($transition->getTos() as $to) {
54+
$edges[$from][] = array(
55+
'name' => $transition->getName(),
56+
'to' => $to,
57+
);
58+
}
59+
}
60+
}
61+
62+
return $edges;
63+
}
64+
65+
/**
66+
* @internal
67+
*/
68+
protected function addEdges(array $edges)
69+
{
70+
$code = '';
71+
72+
foreach ($edges as $id => $edges) {
73+
foreach ($edges as $edge) {
74+
$code .= sprintf(" place_%s -> place_%s [label=\"%s\" style=\"%s\"];\n", $this->dotize($id), $this->dotize($edge['to']), $edge['name'], 'solid');
75+
}
76+
}
77+
78+
return $code;
79+
}
80+
}

‎src/Symfony/Component/Workflow/Tests/Dumper/GraphvizDumperTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Workflow/Tests/Dumper/GraphvizDumperTest.php
+6-6Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public function setUp()
2020
/**
2121
* @dataProvider provideWorkflowDefinitionWithoutMarking
2222
*/
23-
public function testGraphvizDumperWithoutMarking($definition, $expected)
23+
public function testDumpWithoutMarking($definition, $expected)
2424
{
2525
$dump = $this->dumper->dump($definition);
2626

@@ -30,7 +30,7 @@ public function testGraphvizDumperWithoutMarking($definition, $expected)
3030
/**
3131
* @dataProvider provideWorkflowDefinitionWithMarking
3232
*/
33-
public function testWorkflowWithMarking($definition, $marking, $expected)
33+
public function testDumpWithMarking($definition, $marking, $expected)
3434
{
3535
$dump = $this->dumper->dump($definition, $marking);
3636

@@ -40,9 +40,9 @@ public function testWorkflowWithMarking($definition, $marking, $expected)
4040
public function provideWorkflowDefinitionWithMarking()
4141
{
4242
yield array(
43-
$this->createComplexWorkflow(),
43+
$this->createComplexWorkflowDefinition(),
4444
new Marking(array('b' => 1)),
45-
$this->createComplexWorkflowDumpWithMarking(),
45+
$this->createComplexWorkflowDefinitionDumpWithMarking(),
4646
);
4747

4848
yield array(
@@ -54,11 +54,11 @@ public function provideWorkflowDefinitionWithMarking()
5454

5555
public function provideWorkflowDefinitionWithoutMarking()
5656
{
57-
yield array($this->createComplexWorkflow(), $this->provideComplexWorkflowDumpWithoutMarking());
57+
yield array($this->createComplexWorkflowDefinition(), $this->provideComplexWorkflowDumpWithoutMarking());
5858
yield array($this->createSimpleWorkflowDefinition(), $this->provideSimpleWorkflowDumpWithoutMarking());
5959
}
6060

61-
public function createComplexWorkflowDumpWithMarking()
61+
public function createComplexWorkflowDefinitionDumpWithMarking()
6262
{
6363
return 'digraph workflow {
6464
ratio="compress" rankdir="LR"
+74Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
namespace Symfony\Component\Workflow\Tests\Dumper;
4+
5+
use Symfony\Component\Workflow\Dumper\StateMachineGraphvizDumper;
6+
use Symfony\Component\Workflow\Marking;
7+
use Symfony\Component\Workflow\Tests\WorkflowBuilderTrait;
8+
9+
class StateMachineGraphvizDumperTest extends \PHPUnit_Framework_TestCase
10+
{
11+
use WorkflowBuilderTrait;
12+
13+
private $dumper;
14+
15+
public function setUp()
16+
{
17+
$this->dumper = new StateMachineGraphvizDumper();
18+
}
19+
20+
public function testDumpWithoutMarking()
21+
{
22+
$definition = $this->createComplexStateMachineDefinition();
23+
24+
$dump = $this->dumper->dump($definition);
25+
26+
$expected = <<<'EOGRAPH'
27+
digraph workflow {
28+
ratio="compress" rankdir="LR"
29+
node [fontsize="9" fontname="Arial" color="#333333" fillcolor="lightblue" fixedsize="1" width="1"];
30+
edge [fontsize="9" fontname="Arial" color="#333333" arrowhead="normal" arrowsize="0.5"];
31+
32+
place_a [label="a", shape=circle, style="filled"];
33+
place_b [label="b", shape=circle];
34+
place_c [label="c", shape=circle];
35+
place_d [label="d", shape=circle];
36+
place_a -> place_b [label="t1" style="solid"];
37+
place_d -> place_b [label="t1" style="solid"];
38+
place_b -> place_c [label="t2" style="solid"];
39+
place_b -> place_d [label="t3" style="solid"];
40+
}
41+
42+
EOGRAPH;
43+
44+
$this->assertEquals($expected, $dump);
45+
}
46+
47+
public function testDumpWithMarking()
48+
{
49+
$definition = $this->createComplexStateMachineDefinition();
50+
$marking = new Marking(array('b' => 1));
51+
52+
$expected = <<<'EOGRAPH'
53+
digraph workflow {
54+
ratio="compress" rankdir="LR"
55+
node [fontsize="9" fontname="Arial" color="#333333" fillcolor="lightblue" fixedsize="1" width="1"];
56+
edge [fontsize="9" fontname="Arial" color="#333333" arrowhead="normal" arrowsize="0.5"];
57+
58+
place_a [label="a", shape=circle, style="filled"];
59+
place_b [label="b", shape=circle, color="#FF0000", shape="doublecircle"];
60+
place_c [label="c", shape=circle];
61+
place_d [label="d", shape=circle];
62+
place_a -> place_b [label="t1" style="solid"];
63+
place_d -> place_b [label="t1" style="solid"];
64+
place_b -> place_c [label="t2" style="solid"];
65+
place_b -> place_d [label="t3" style="solid"];
66+
}
67+
68+
EOGRAPH;
69+
70+
$dump = $this->dumper->dump($definition, $marking);
71+
72+
$this->assertEquals($expected, $dump);
73+
}
74+
}

0 commit comments

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