Passed
Branch php-scrutinizer (0ac9d8)
by Jens
09:19
created

Renderer::renderDot()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 23
ccs 0
cts 15
cp 0
rs 9.0856
c 0
b 0
f 0
cc 3
eloc 11
nc 4
nop 1
crap 12
1
<?php
2
/**
3
 * @author @jenschude <[email protected]>
4
 */
5
6
namespace Commercetools\Core\Helper\State;
7
8
use Commercetools\Core\Client;
9
use Commercetools\Core\Model\Common\Context;
10
use Commercetools\Core\Helper\State\Renderer\NodeRenderer;
11
use Commercetools\Core\Helper\State\Renderer\TransitionRenderer;
12
use Commercetools\Core\Model\State\StateCollection;
13
use Commercetools\Core\Request\States\StateQueryRequest;
14
15
class Renderer
16
{
17
    /** @var array Colors for drawing dwh states */
18
    public static $colors = array(
19
        '#2266aa',
20
        '#228866',
21
        '#775533',
22
        '#333311',
23
        '#881122',
24
        '#662266',
25
        '#00212E',
26
        '#42002E',
27
        '#422100',
28
        '#000B11',
29
        '#5A0011',
30
        '#5A0B00'
31
    );
32
33
    /** @var array $eventColors colors for drawing the events */
34
    protected $eventColors = array(
35
        'manual'  => '#00AA00',     // color for manually executable event
36
        'timeout' => '#AAAAAA',     // color for timeout event
37
        'statewasset' => '#0000AA',     // color for other events
38
        'default' => '#222222',     // color for other events
39
    );
40
41
    /** @var string $defaultFontColor default font color for state nodes */
42
    protected $defaultFontColor = '';
43
    /** @var string $defaultBorderColor default border color for state nodes */
44
    protected $defaultBorderColor = '';
45
46
    /**
47
     * @var array $nodeRenderers contains the renderers for the state nodes.
48
     *
49
     * They can be set by setNodeRendererByStateName(). If no renderer is set the default renderer
50
     * Bob_StateMachine_Renderer_Node_DefaultRenderer will be used.
51
     */
52
    protected $nodeRenderers = array();
53
54
    protected $transitionRenderers = array();
55
56
    /**
57
     * @return array
58
     */
59
    public function getEventColors()
60
    {
61
        return $this->eventColors;
62
    }
63
64
    /**
65
     * @param array $eventColors
66
     */
67
    public function setEventColors($eventColors)
68
    {
69
        $this->eventColors = $eventColors;
70
    }
71
72
    /**
73
     * @return string
74
     */
75
    public function getDefaultFontColor()
76
    {
77
        return $this->defaultFontColor;
78
    }
79
80
    /**
81
     * @param string $defaultFontColor
82
     */
83
    public function setDefaultFontColor($defaultFontColor)
84
    {
85
        $this->defaultFontColor = $defaultFontColor;
86
    }
87
88
    /**
89
     * @return string
90
     */
91
    public function getDefaultBorderColor()
92
    {
93
        return $this->defaultBorderColor;
94
    }
95
96
    /**
97
     * @param string $defaultBorderColor
98
     */
99
    public function setDefaultBorderColor($defaultBorderColor)
100
    {
101
        $this->defaultBorderColor = $defaultBorderColor;
102
    }
103
104
    /**
105
     * @return array
106
     */
107
    public function getNodeRenderers()
108
    {
109
        return $this->nodeRenderers;
110
    }
111
112
    /**
113
     * @param array $nodeRenderers
114
     */
115
    public function setNodeRenderers($nodeRenderers)
116
    {
117
        $this->nodeRenderers = $nodeRenderers;
118
    }
119
120
    /**
121
     * @return array
122
     */
123
    public function getTransitionRenderers()
124
    {
125
        return $this->transitionRenderers;
126
    }
127
128
    /**
129
     * @param array $transitionRenderers
130
     */
131
    public function setTransitionRenderers($transitionRenderers)
132
    {
133
        $this->transitionRenderers = $transitionRenderers;
134
    }
135
136
    /**
137
     * Is there a state node renderer for the given state name?
138
     *
139
     * @param $stateName
140
     * @return bool
141
     */
142
    public function hasNodeRendererByStateName($stateName)
143
    {
144
        return isset($this->nodeRenderers[$stateName]);
145
    }
146
147
    /**
148
     * Get the renderer for the given state name.
149
     *
150
     * If no renderer was set the default renderer Bob_StateMachine_Renderer_Node_DefaultRenderer() is returned
151
     *
152
     * @param $stateName
153
     * @return NodeRenderer
154
     */
155
    public function getNodeRendererByStateName($stateName)
156
    {
157
        if (isset($this->nodeRenderers[$stateName])) {
158
            return $this->nodeRenderers[$stateName];
159
        }
160
        return new NodeRenderer();
161
    }
162
163
    public function getTransitionRendererByStateName($stateName)
164
    {
165
        if (isset($this->transitionRenderers[$stateName])) {
166
            return $this->transitionRenderers[$stateName];
167
        }
168
        return new TransitionRenderer();
169
    }
170
171
    /**
172
     * Renders a dot graph into an svg
173
     *
174
     * @param string $dotString The dot graph that is fed into the
175
     * @return string|bool the resulting SVG
176
     */
177
    public function runDot($dotString)
178
    {
179
        $descriptorSpec = array(
180
            0 => array("pipe", "r"), // stdin
181
            1 => array("pipe", "w"), // stdout
182
            2 => array("pipe", "a") // stderr
183
        );
184
185
        $process = proc_open('dot -Tsvg', $descriptorSpec, $pipes);
186
187
        if (is_resource($process)) {
188
            fwrite($pipes[0], $dotString);
189
            fclose($pipes[0]);
190
191
            $svg = stream_get_contents($pipes[1]);
192
            fclose($pipes[1]);
193
194
            proc_close($process);
195
            $svg = explode('<svg ', $svg);
196
197
            // has it worked out?
198
            if (count($svg) < 2) {
199
                return false;
200
            }
201
202
            return '<svg ' . $svg[1];
203
        }
204
205
        return false;
206
    }
207
208
    /**
209
     * Creates a dot graph for a process
210
     *
211
     * @param StateCollection $stateCollection
212
     * @return string A dot graph
213
     */
214
    public function renderDot(StateCollection $stateCollection)
215
    {
216
        // define the graph
217
        $graph = 'digraph ' . 'test'
218
            . ' { dpi="56";compound="true";fontname="Arial";margin="";nodesep="0.6";rankdir="TD";ranksep="0.4";'
219
            . PHP_EOL;
220
221
        // add all states to the graph
222
        foreach ($stateCollection as $state) {
223
            $nodeRenderer = $this->getNodeRendererByStateName($state->getKey());
224
            $graph .= ' ' . $nodeRenderer->render($state);
225
        }
226
227
        // add all transitions to the graph
228
        foreach ($stateCollection as $state) {
229
            $nodeRenderer = $this->getTransitionRendererByStateName($state->getKey());
230
            $graph .= ' ' . $nodeRenderer->render($state);
231
        }
232
233
        $graph .= '}' . PHP_EOL;
234
235
236
        return $graph;
237
    }
238
239
    /**
240
     * @param Client $client
241
     * @param Context $context
242
     * @return string
243
     */
244
    public static function run(Client $client, Context $context = null)
245
    {
246
        $renderer = new static();
247
        $request = new StateQueryRequest($context);
248
        $request->expand('transitions[*]');
249
250
        $states = $client->execute($request)->toObject();
251
252
        $dotString = $renderer->renderDot($states);
253
        return $renderer->runDot($dotString);
254
    }
255
}
256